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.

 
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.

 
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.

 
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)。

  

 const int N = , SQRTN = , M = ;
int n, m;
int value[N];
int depth[N], father[N], dfsList[N];
vector<int> force[N]; struct AdjacencyList {
int head[N], son[N * ], nex[N * ], tot; inline void init(int n = N) {
for(int i = ; i < n; ++i) head[i] = -;
tot = ;
} inline void addEdge(int u, int v) {
son[tot] = v, nex[tot] = head[u];
head[u] = tot++;
} int que[N], len, size[N], pos[N];
bool visit[N];
inline void build(int n, int depth[], int fa[], int dfs[]) {
for(int i = ; i < n; ++i) visit[i] = false, size[i] = ;
len = , que[] = , fa[] = -, depth[] = , visit[] = true;
for(int hed = ; hed < len; ++hed) {
int u = que[hed];
for(int v, tab = head[u]; tab != -; tab = nex[tab])
if(visit[v = son[tab]] == false) {
visit[v] = true, fa[v] = u, depth[v] = depth[u] + ;
que[len++] = v;
}
} for(int i = len - ; i >= ; --i) {
++size[i];
if(fa[i] != -) size[fa[i]] += size[i];
}
dfs[] = , pos[] = ;
for(int i = ; i < len; ++i) {
int u = que[i];
for(int cnt = , tab = head[u], v; tab != -; tab = nex[tab])
if((v = son[tab]) != fa[u]) {
pos[v] = pos[u] + cnt + ;
dfs[pos[v]] = v;
cnt += size[v];
}
}
}
} edge; struct ST {
int fa[N][M], *depth; inline void init(int n, int father[], int tdepth[]) {
depth = tdepth;
for(int i = ; i < n; ++i) fa[i][] = father[i];
for(int dep = ; dep < M; ++dep)
for(int i = ; i < n; ++i)
if(fa[i][dep - ] != -)
fa[i][dep] = fa[fa[i][dep - ]][dep - ];
else fa[i][dep] = -;
} inline int getLca(int u, int v) {
if(depth[u] < depth[v]) swap(u, v);
for(int dep = M - ; dep >= ; --dep)
if(fa[u][dep] != - && depth[fa[u][dep]] >= depth[v])
u = fa[u][dep];
if(u == v) return u;
for(int dep = M - ; dep >= ; --dep)
if(fa[u][dep] != - && fa[u][dep] != fa[v][dep])
u = fa[u][dep], v = fa[v][dep];
return fa[u][];
} inline int getFather(int u, int step) {
for(int dep = M - ; dep >= ; --dep)
if(fa[u][dep] != - && ( << dep) <= step)
u = fa[u][dep], step -= ( << dep);
return u;
}
} st; struct Query {
int u, v, k, lca, ans, id; inline void read() {
scanf("%d%d%d", &u, &v, &k);
--u, --v;
lca = st.getLca(u, v), ans = ;
} inline void upd(int x) {
if(ans < x) ans = x;
} inline void fix(int &u, int lca, int jump, int depth[]) {
if(depth[u] - depth[lca] >= jump) {
u = st.getFather(u, jump);
upd(value[u]);
} else u = lca;
} inline void fix(int depth[]) {
if((depth[u] - depth[lca] + ) % k == ) upd(value[lca]);
fix(v, lca, (depth[u] + depth[v] - depth[lca] * + ) % k, depth);
fix(u, lca, k - , depth);
} inline operator <(const Query &t) const {
return k < t.k;
}
} query[N]; struct SolutionForLessThanSqrtN {
int jump[N], cnt[N], que[N], top;
int f[N], g[N];
vector<int> wait[N]; inline void init(int n, int value[], int depth[], int dfs[], int k) {
for(int i = ; i < n; ++i) wait[i].clear();
for(int i = ; i < n; ++i) f[i] = i, g[i] = value[i]; top = -;
for(int i = ; i < n; ++i) cnt[i] = -;
for(int i = ; i < n; ++i) {
int u = dfs[i];
while(top >= && depth[u] != depth[que[top - ]] + ) --top;
que[++top] = u;
if(depth[u] < k) jump[u] = -;
else jump[u] = cnt[depth[u] - k];
cnt[depth[u]] = u;
}
} inline void add(int idx) {
wait[query[idx].lca].pub(idx);
} inline int expose(int x, int lim = -, int *depth = NULL) {
if(x == lim) return ;
if(x == f[x]) return g[x];
if(depth != NULL && depth[f[x]] <= depth[lim]) return g[x];
int t = f[x];
expose(f[x], lim, depth);
f[x] = f[t], g[x] = max(g[x], g[t]);
return g[x];
} inline void merge(int u, int v) {
expose(u), expose(v);
f[f[u]] = f[v];
} inline void solve(int n, int dfs[], int depth[]) {
for(int i = n - ; i >= ; --i) {
int u = dfs[i];
foreach(idx, wait[u]) {
int i = *idx;
query[i].upd(expose(query[i].u, query[i].lca, depth));
query[i].upd(expose(query[i].v, query[i].lca, depth));
}
if(jump[u] != -) merge(u, jump[u]);
}
}
} solver; inline bool cmpByIndex(const Query &a, const Query &b) {
return a.id < b.id;
} int myStack[N], top; inline void updata(int x, int g, int q, int depth[]) {
while(x >= query[q].k && depth[myStack[x - query[q].k]] > depth[g]) {
x -= query[q].k;
query[q].upd(value[myStack[x]]);
}
} inline void solve() {
for(int i = ; i < m; ++i) query[i].fix(depth);
for(int i = ; i < n; ++i) force[i].clear();
sort(query, query + m); int limit = floor(sqrt(n));
for(int i = , j; i < m; i = j + )
if(query[i].k <= limit) {
for(j = i; j < m - && query[j + ].k == query[i].k; ++j);
solver.init(n, value, depth, dfsList, query[i].k);
for(int k = i; k <= j; ++k) solver.add(k);
solver.solve(n, dfsList, depth);
} else force[query[i].u].pub(i), force[query[i].v].pub(i), j = i; top = -;
for(int i = ; i < n; ++i) {
int x = dfsList[i];
while(top >= && depth[x] != depth[myStack[top]] + ) --top;
myStack[++top] = x;
foreach(q, force[x])
updata(top, query[*q].lca, *q, depth);
} sort(query, query + m, cmpByIndex);
for(int i = ; i < m; ++i) printf("%d\n", query[i].ans);
} int main() {
int testCase;
scanf("%d", &testCase);
for(int testIndex = ; testIndex <= testCase; ++testIndex) {
scanf("%d%d", &n, &m);
edge.init();
for(int i = ; i < n; ++i) scanf("%d", &value[i]);
for(int i = , v, u; i < n - ; ++i) {
scanf("%d%d", &u, &v);
--u, --v;
edge.addEdge(u, v), edge.addEdge(v, u);
}
edge.build(n, depth, father, dfsList);
st.init(n, father, depth);
for(int i = ; i < m; ++i) query[i].id = i, query[i].read();
printf("Case #%d:\n", testIndex);
solve();
}
return ;
}

2016中国大学生程序设计竞赛 网络选拔赛 I This world need more Zhu的更多相关文章

  1. 2016中国大学生程序设计竞赛 - 网络选拔赛 C. Magic boy Bi Luo with his excited tree

    Magic boy Bi Luo with his excited tree Problem Description Bi Luo is a magic boy, he also has a migi ...

  2. 2016中国大学生程序设计竞赛 - 网络选拔赛 J. Alice and Bob

    Alice and Bob Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  3. 2016中国大学生程序设计竞赛 - 网络选拔赛 1004 Danganronpa

    Problem Description Chisa Yukizome works as a teacher in the school. She prepares many gifts, which ...

  4. 2016中国大学生程序设计竞赛 - 网络选拔赛 1011 Lweb and String

    Problem Description Lweb has a string S. Oneday, he decided to transform this string to a new sequen ...

  5. 2016中国大学生程序设计竞赛 - 网络选拔赛 1001 A water problem (大数取余)

    Problem Descripton Two planets named Haha and Xixi in the universe and they were created with the un ...

  6. 2018中国大学生程序设计竞赛 - 网络选拔赛 1001 - Buy and Resell 【优先队列维护最小堆+贪心】

    题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6438 Buy and Resell Time Limit: 2000/1000 MS (Java/O ...

  7. 2018中国大学生程序设计竞赛 - 网络选拔赛 1010 YJJ's Salesman 【离散化+树状数组维护区间最大值】

    题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6447 YJJ's Salesman Time Limit: 4000/2000 MS (Java/O ...

  8. 2018中国大学生程序设计竞赛 - 网络选拔赛 1009 - Tree and Permutation 【dfs+树上两点距离和】

    Tree and Permutation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Oth ...

  9. HDU 6154 - CaoHaha's staff | 2017 中国大学生程序设计竞赛 - 网络选拔赛

    /* HDU 6154 - CaoHaha's staff [ 构造,贪心 ] | 2017 中国大学生程序设计竞赛 - 网络选拔赛 题意: 整点图,每条线只能连每个方格的边或者对角线 问面积大于n的 ...

随机推荐

  1. Redis中持久化的两种方法详解

    Redis提供了两种不同的持久化方法来将数据存储到硬盘里面.一种方法叫快照(snapshotting),它可以将存在于某一时刻的所有数据都写入硬盘里;另一种方法教只追加文件(append-only f ...

  2. 11月1日上午PHP------empty、 is_null、isset、unset的区别

    1.empty 判断一个变量是否为"空".null.false.00.0.'0′.』.为以上值的变量在检测時都将返回true. 2.isset 判断一个变量是否已经设置.0.00. ...

  3. codevs1021 玛丽卡

    题目描述 Description 麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复. 因为她和他们不住在同一个城市,因此她开始准备她的长途旅行. 在这个国家中每两个城市之间最多只有一条路相通,并且我们 ...

  4. UIScrollView的缩放原理

    当用户在UIScrollView身上使用捏合手势时,UIScrollView会给代理发送一条消息,询问代理究竟要缩放自己内部的哪一个子控件(哪一块内容) 当用户在UIScrollView身上使用捏合手 ...

  5. PHP函数call_user_func和call_user_func_array详解

    今天在群里面,有个叫lewis的在问call_user_func_array的用法,因为之前一直没有用过,也不能说什么,于是看一下手册,发现是这么写的: call_user_func_array (P ...

  6. Alpha版本十天冲刺——Day 10

    站立式会议 最后一天,很高兴我们做出了跟预期差不多的版本,实现了基本功能,虽然还有一些bug,但是下一阶段我们会继续加油! 会议总结 队员 今天完成 遇到的问题 感想 鲍亮 功能细节更改 我的手机运行 ...

  7. python虚拟机中的异常流控制

    异常:对程序运行中的非正常情况进行抽象.并且提供相应的语法结构和语义元素,使得程序员能够通过这些语法结构和语义元素来方便地描述异常发生时的行为. 1.Python中的异常机制: 1.1Python虚拟 ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. python运算符

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcIAAAHCCAIAAADzel4SAAAgAElEQVR4Aey9+bMcSXLnV1dmna/ejR

  10. linux下 chown命令

    对Document/ 目录下的所有文件与子目录执行相同的所有者变更,修改所有者为users用户组的username用户 chown -R username:users Document/ userna ...