This world need more Zhu
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 262 Accepted Submission(s): 49
Problem Description
As we all know, Zhu is the most powerful man. He has the infinite power to protest the world. We need more men like Zhu!
In Duoladuo, this place is like a tree. There are n vertices and n−1 edges. And the root is 1. Each vertex can reached by any other vertices. Each vertex has a people with value Ai named Zhu's believer.
Liao is a curious baby, he has m questions to ask Zhu. But now Zhu is busy, he wants you to help him answer Liao's questions.
Liao's question will be like "u v k".
That means Liao want to know the answer from following code:
ans = 0; cnt = 0;
for x in the shortest path from u to v {
cnt++;
if(cnt mod k == 0) ans = max(ans,a[x]);
}
print(ans).
Please read the hints for more details.
In Duoladuo, this place is like a tree. There are n vertices and n−1 edges. And the root is 1. Each vertex can reached by any other vertices. Each vertex has a people with value Ai named Zhu's believer.
Liao is a curious baby, he has m questions to ask Zhu. But now Zhu is busy, he wants you to help him answer Liao's questions.
Liao's question will be like "u v k".
That means Liao want to know the answer from following code:
ans = 0; cnt = 0;
for x in the shortest path from u to v {
cnt++;
if(cnt mod k == 0) ans = max(ans,a[x]);
}
print(ans).
Please read the hints for more details.
Input
In the first line contains a single positive integer
T, indicating number of test case.
In the second line there are two numbers n, m. n is the size of Duoladuo, m is the number of Liao's questions.
The next line contains n integers A1,A2,...An, means the value of ith vertex.
In the next n−1 line contains tow numbers u, v. It means there is an edge between vertex u and vertex v.
The next m lines will be the Liao's question:
u v k
1≤T≤10,1≤n≤100000,1≤m≤100000,1≤u,v≤n,1≤k, Ai≤1000000000.
In the second line there are two numbers n, m. n is the size of Duoladuo, m is the number of Liao's questions.
The next line contains n integers A1,A2,...An, means the value of ith vertex.
In the next n−1 line contains tow numbers u, v. It means there is an edge between vertex u and vertex v.
The next m lines will be the Liao's question:
u v k
1≤T≤10,1≤n≤100000,1≤m≤100000,1≤u,v≤n,1≤k, Ai≤1000000000.
Output
For each case, output Case #i: (i is the number of the test case, from 1 to
T).
Then, you need to output the answer for every Liao's questions.
Then, you need to output the answer for every Liao's questions.
Sample Input
1 5 5 1 2 4 1 2 1 2 2 3 3 4 4 5 1 1 1 1 3 2 1 3 100 1 5 2 1 3 1
Sample Output
Case #1: 1 2 0 2 4
Hint
In query 1,there are only one vertex in the path,so the answer is 1. In query 2,there are three vertices in the path.But only the vertex 2 mod 2 equals to 0. In query 3,there are three vertices in the path.But no vertices mod 100 equal to 0. In query 4,there are five vertices in the path.There are two vertices mod 2 equal to 0.So the answer is max(a[2],a[4]) = 2. In query 5,there are three vertices in the path.And all the vertices mod 1 equal to 0. So the answer is a[3] = 4.
Author
UESTC
题意:
给出一棵树,每次询问从u,v,k,代表如果从u到v的路径上的节点从一开始编号的话,编号为k的倍数的节点的权值最大值是多少?
题解:
分k的大小进行讨论
1、当k大于sqrt(n)时,可以进行暴力。
可以知道对于任意一次路径,如果可以O(1)寻找到k步之后的节点的话,不会超过sqrt(n)的节点需要统计。
总复杂度O(sqrt(n))。
O(1)寻找k步之后的节点,我的做法需要离线。
u到lca(u,v)再到v的过程可以看作u到lca(u,v),v到lca(u,v)两部分。
如果对u,v进行修正(往上跳到第一个选取的节点O(logn)或者O(1)),可以认为两部分的询问都是在一条链上进行的。
所以在使用人工栈进行dfs的话,可以O(1)在栈中找到往上k步的节点。
2、当k小于sqrt(n),对于每种k都可以单独处理出所有询问答案。
用类似tarjan求lca的方法,每次对于每种k先O(n)预处理出所有点向上跳K步的父亲。
事实上,某个节点向上k步的父亲就是在dfs序中在在其左侧最近的深度恰好比起高k的节点。
然后进行类似tarjan的过程,只不过每次做并查集时与向上跳K步的父亲merge。
并且在做路径压缩时顺便记录下当前路径的最大值,并且路径压缩到lca为止。
当然,需要预先处理出所有询问u,v的lca。
每次对于某种K,复杂度O(n)
总复杂度O(m sqrt(n)。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 const int N = 100010, SQRTN = 350, M = 20; 2 int n, m; 3 int value[N]; 4 int depth[N], father[N], dfsList[N]; 5 vector<int> force[N]; 6 7 struct AdjacencyList { 8 int head[N], son[N * 2], nex[N * 2], tot; 9 10 inline void init(int n = N) { 11 for(int i = 0; i < n; ++i) head[i] = -1; 12 tot = 0; 13 } 14 15 inline void addEdge(int u, int v) { 16 son[tot] = v, nex[tot] = head[u]; 17 head[u] = tot++; 18 } 19 20 int que[N], len, size[N], pos[N]; 21 bool visit[N]; 22 inline void build(int n, int depth[], int fa[], int dfs[]) { 23 for(int i = 0; i < n; ++i) visit[i] = false, size[i] = 0; 24 len = 1, que[0] = 0, fa[0] = -1, depth[0] = 0, visit[0] = true; 25 for(int hed = 0; hed < len; ++hed) { 26 int u = que[hed]; 27 for(int v, tab = head[u]; tab != -1; tab = nex[tab]) 28 if(visit[v = son[tab]] == false) { 29 visit[v] = true, fa[v] = u, depth[v] = depth[u] + 1; 30 que[len++] = v; 31 } 32 } 33 34 for(int i = len - 1; i >= 0; --i) { 35 ++size[i]; 36 if(fa[i] != -1) size[fa[i]] += size[i]; 37 } 38 dfs[0] = 0, pos[0] = 0; 39 for(int i = 0; i < len; ++i) { 40 int u = que[i]; 41 for(int cnt = 0, tab = head[u], v; tab != -1; tab = nex[tab]) 42 if((v = son[tab]) != fa[u]) { 43 pos[v] = pos[u] + cnt + 1; 44 dfs[pos[v]] = v; 45 cnt += size[v]; 46 } 47 } 48 } 49 } edge; 50 51 struct ST { 52 int fa[N][M], *depth; 53 54 inline void init(int n, int father[], int tdepth[]) { 55 depth = tdepth; 56 for(int i = 0; i < n; ++i) fa[i][0] = father[i]; 57 for(int dep = 1; dep < M; ++dep) 58 for(int i = 0; i < n; ++i) 59 if(fa[i][dep - 1] != -1) 60 fa[i][dep] = fa[fa[i][dep - 1]][dep - 1]; 61 else fa[i][dep] = -1; 62 } 63 64 inline int getLca(int u, int v) { 65 if(depth[u] < depth[v]) swap(u, v); 66 for(int dep = M - 1; dep >= 0; --dep) 67 if(fa[u][dep] != -1 && depth[fa[u][dep]] >= depth[v]) 68 u = fa[u][dep]; 69 if(u == v) return u; 70 for(int dep = M - 1; dep >= 0; --dep) 71 if(fa[u][dep] != -1 && fa[u][dep] != fa[v][dep]) 72 u = fa[u][dep], v = fa[v][dep]; 73 return fa[u][0]; 74 } 75 76 inline int getFather(int u, int step) { 77 for(int dep = M - 1; dep >= 0; --dep) 78 if(fa[u][dep] != -1 && (1 << dep) <= step) 79 u = fa[u][dep], step -= (1 << dep); 80 return u; 81 } 82 } st; 83 84 struct Query { 85 int u, v, k, lca, ans, id; 86 87 inline void read() { 88 scanf("%d%d%d", &u, &v, &k); 89 --u, --v; 90 lca = st.getLca(u, v), ans = 0; 91 } 92 93 inline void upd(int x) { 94 if(ans < x) ans = x; 95 } 96 97 inline void fix(int &u, int lca, int jump, int depth[]) { 98 if(depth[u] - depth[lca] >= jump) { 99 u = st.getFather(u, jump); 100 upd(value[u]); 101 } else u = lca; 102 } 103 104 inline void fix(int depth[]) { 105 if((depth[u] - depth[lca] + 1) % k == 0) upd(value[lca]); 106 fix(v, lca, (depth[u] + depth[v] - depth[lca] * 2 + 1) % k, depth); 107 fix(u, lca, k - 1, depth); 108 } 109 110 inline operator <(const Query &t) const { 111 return k < t.k; 112 } 113 } query[N]; 114 115 struct SolutionForLessThanSqrtN { 116 int jump[N], cnt[N], que[N], top; 117 int f[N], g[N]; 118 vector<int> wait[N]; 119 120 inline void init(int n, int value[], int depth[], int dfs[], int k) { 121 for(int i = 0; i < n; ++i) wait[i].clear(); 122 for(int i = 0; i < n; ++i) f[i] = i, g[i] = value[i]; 123 124 top = -1; 125 for(int i = 0; i < n; ++i) cnt[i] = -1; 126 for(int i = 0; i < n; ++i) { 127 int u = dfs[i]; 128 while(top >= 0 && depth[u] != depth[que[top - 1]] + 1) --top; 129 que[++top] = u; 130 if(depth[u] < k) jump[u] = -1; 131 else jump[u] = cnt[depth[u] - k]; 132 cnt[depth[u]] = u; 133 } 134 } 135 136 inline void add(int idx) { 137 wait[query[idx].lca].pub(idx); 138 } 139 140 inline int expose(int x, int lim = -1, int *depth = NULL) { 141 if(x == lim) return 0; 142 if(x == f[x]) return g[x]; 143 if(depth != NULL && depth[f[x]] <= depth[lim]) return g[x]; 144 int t = f[x]; 145 expose(f[x], lim, depth); 146 f[x] = f[t], g[x] = max(g[x], g[t]); 147 return g[x]; 148 } 149 150 inline void merge(int u, int v) { 151 expose(u), expose(v); 152 f[f[u]] = f[v]; 153 } 154 155 inline void solve(int n, int dfs[], int depth[]) { 156 for(int i = n - 1; i >= 0; --i) { 157 int u = dfs[i]; 158 foreach(idx, wait[u]) { 159 int i = *idx; 160 query[i].upd(expose(query[i].u, query[i].lca, depth)); 161 query[i].upd(expose(query[i].v, query[i].lca, depth)); 162 } 163 if(jump[u] != -1) merge(u, jump[u]); 164 } 165 } 166 } solver; 167 168 inline bool cmpByIndex(const Query &a, const Query &b) { 169 return a.id < b.id; 170 } 171 172 int myStack[N], top; 173 174 inline void updata(int x, int g, int q, int depth[]) { 175 while(x >= query[q].k && depth[myStack[x - query[q].k]] > depth[g]) { 176 x -= query[q].k; 177 query[q].upd(value[myStack[x]]); 178 } 179 } 180 181 inline void solve() { 182 for(int i = 0; i < m; ++i) query[i].fix(depth); 183 for(int i = 0; i < n; ++i) force[i].clear(); 184 sort(query, query + m); 185 186 int limit = floor(sqrt(n)); 187 for(int i = 0, j; i < m; i = j + 1) 188 if(query[i].k <= limit) { 189 for(j = i; j < m - 1 && query[j + 1].k == query[i].k; ++j); 190 solver.init(n, value, depth, dfsList, query[i].k); 191 for(int k = i; k <= j; ++k) solver.add(k); 192 solver.solve(n, dfsList, depth); 193 } else force[query[i].u].pub(i), force[query[i].v].pub(i), j = i; 194 195 top = -1; 196 for(int i = 0; i < n; ++i) { 197 int x = dfsList[i]; 198 while(top >= 0 && depth[x] != depth[myStack[top]] + 1) --top; 199 myStack[++top] = x; 200 foreach(q, force[x]) 201 updata(top, query[*q].lca, *q, depth); 202 } 203 204 sort(query, query + m, cmpByIndex); 205 for(int i = 0; i < m; ++i) printf("%d\n", query[i].ans); 206 } 207 208 int main() { 209 int testCase; 210 scanf("%d", &testCase); 211 for(int testIndex = 1; testIndex <= testCase; ++testIndex) { 212 scanf("%d%d", &n, &m); 213 edge.init(); 214 for(int i = 0; i < n; ++i) scanf("%d", &value[i]); 215 for(int i = 0, v, u; i < n - 1; ++i) { 216 scanf("%d%d", &u, &v); 217 --u, --v; 218 edge.addEdge(u, v), edge.addEdge(v, u); 219 } 220 edge.build(n, depth, father, dfsList); 221 st.init(n, father, depth); 222 for(int i = 0; i < m; ++i) query[i].id = i, query[i].read(); 223 printf("Case #%d:\n", testIndex); 224 solve(); 225 } 226 return 0; 227 }