Link

等差数列

直接算

小道消息

先把n++, k++,若kk是个质数,且k[n2,n]k\in[\frac{n}{2}, n],那么答案为11

否则,因为n2,n]\frac{n}{2}, n]之间一定有个质数,所以答案为22

核心城市

[贪心] [堆]

贪心,显然直径的中点是必须要选的。预处理从每个点往下走的最长的dep,以这个为关键字建堆,每次找到最大的点选进答案集合,再把它所有儿子加入堆中

系统设计

[Hash] [线段树] [数据结构]

xx开始遍历可以看作先从根开始走到xx,再往下走。将根到节点xx的简单路径依次经过的边的排名记作⼀个字符串sxs_x,每次询问[x,l,r][x, l, r]时,就相当于查询sx+al,rs_x + a_{l, r}(这里+就是直接连接)这个字符串在树种最长能匹配到哪个点

可以直接Hash,预处理每个节点的ss,存在哈希表中。用线段树维护aa的哈希值,查询时在线段树上二分即可

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <bits/stdc++.h>
#include <bits/extc++.h>

#define x first
#define y second
#define y1 Y1
#define y2 Y2
#define mp make_pair
#define pb push_back
#define DEBUG(x) cout << #x << " = " << x << endl;

using namespace std;
using namespace __gnu_pbds;

typedef long long LL;
typedef pair <int, int> pii;

template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; }
template <typename T> inline T read ()
{
T sum = 0, fl = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
return sum * fl;
}

inline void proc_status ()
{
ifstream t ("/proc/self/status");
cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) << endl;
}

const int MAXN = 5e5;

int N, M, Q, o;
int A[MAXN + 5];

namespace HASH
{
typedef unsigned long long ULL;

const ULL base = 20030123;

ULL Val[MAXN + 5], Hash[MAXN + 5], mul[MAXN + 5];
gp_hash_table <ULL, int> Map;

struct info
{
ULL val; int len;

info (ULL _val = 0, int _len = 0) { val = _val, len = _len; }

};

inline info merge (info x, info y)
{
info o;
o.len = x.len + y.len;
o.val = x.val * mul[y.len] + y.val;
return o;
}

int fg;

namespace SEG
{
#define mid ((l + r) >> 1)
#define ls o << 1
#define rs o << 1 | 1
#define lson ls, l, mid
#define rson rs, mid + 1, r

const int MAX_NODE = MAXN * 4;

info node[MAX_NODE + 5];

inline void push_up (int o) { node[o] = merge (node[ls], node[rs]); }

inline void build (int o, int l, int r)
{
if (l == r) return void (node[o] = info (Val[A[l]], 1));
build (lson), build (rson);
push_up (o);
}

inline void modify (int o, int l, int r, int x, ULL val)
{
if (l == r) return void (node[o] = info (val, 1));
if (x <= mid) modify (lson, x, val);
else modify (rson, x, val);
push_up (o);
}

inline void query (int o, int l, int r, int x, int y, info &res)
{
if (fg) return ;
if (x <= l && r <= y)
{
if (Map[merge (res, node[o]).val]) { res = merge (res, node[o]); return ; }
else if (l == r) { fg = 1; return ; }
}

if (x <= mid) query (lson, x, y, res);
if (y > mid) query (rson, x, y, res);
}

#undef mid
}

inline void init ()
{
for (int i = 1; i <= N; ++i) Val[i] = (ULL) rand() * rand() * rand() + (ULL) rand() * rand() + rand();
mul[0] = 1;
for (int i = 1; i <= N; ++i) mul[i] = mul[i - 1] * base;
}
}

using namespace HASH;

vector <int> G[MAXN + 5];

inline void dfs (int x, int f, ULL hash)
{
Hash[x] = hash;
Map[hash] = x;
sort (G[x].begin(), G[x].end());

for (int i = 0; i < G[x].size(); ++i)
{
int y = G[x][i]; if (y == f) continue;
dfs (y, x, hash * base + Val[i + 1]);
}
}

inline void Solve ()
{
HASH :: init ();
dfs (o, 0, 0); SEG :: build (1, 1, M);

while (Q--)
{
int op = read<int>(), x = read<int>();
if (op == 1)
{
int ql = read<int>(), qr = read<int>();
info now (Hash[x], 1);

fg = 0;
SEG :: query (1, 1, M, ql, qr, now);
printf("%d\n", Map[now.val]);
}
else
{
int y = read<int>();
SEG :: modify (1, 1, M, x, Val[y]);
}
}
}

inline void Input ()
{
N = read<int>(), M = read<int>(), Q = read<int>();
for (int i = 1; i <= N; ++i)
{
int f = read<int>();
if (!f) o = i;
else G[f].pb (i);
}
for (int i = 1; i <= M; ++i) A[i] = read<int>();
}

int main()
{

#ifndef ONLINE_JUDGE
freopen("D.in", "r", stdin);
freopen("D.out", "w", stdout);
#endif

Input ();
Solve ();

return 0;
}

Namid[A]me

[暴力]

VV为最大权值

正解要离散对数O(P)O(P)预处理xxx^x,我直接快速幂logP\log P算的也能过。。。

考虑每个叶子到根的路径上,最多只会有logV\log V种不同的权值,于是考虑暴力对每个点维护它子树里所有被取到的值和分别取到了多少次

因为叶子个数很少,所以这样做复杂度其实是对的。因为任意两个叶子只会在它们的lca处产生复杂度为(logV)2(\log V) ^ 2的贡献,所以最多产生O(dlogV)2O(d\log V)^2的复杂度;又因为每条路径肯定只会被算一次,即复杂度不会超过O(n2)O(n^2),所以总复杂度为min{n2,(dlogV)2}\min \{n^2, (d\log V)^2\}。又因为min{a,b}ab\min \{a, b\} \le \sqrt{ab},所以复杂度为O(ndlogV)O(nd \log V)