HDU 4718 The LCIS on the Tree 树上路径倍增
2015-08-05 10:01
555 查看
[align=left]Problem Description[/align]
For a sequence S1, S2, ... , SN, and a pair of integers (i, j), if 1 <= i <= j <= N and Si
< Si+1 < Si+2 < ... < Sj-1 < Sj , then the sequence Si,
Si+1, ... , Sj is aCIS (Continuous Increasing Subsequence). The longestCIS of a sequence is called theLCIS (Longest
Continuous Increasing Subsequence).
Now we consider a tree rooted at node 1. Nodes have values. We have Q queries, each with two nodes u and v. You have to find the shortest path from u to v. And write down each nodes' value on the path, from u to v, inclusive. Then you will get a sequence, and
please show us the length of its LCIS.
[align=left]Input[/align]
The first line has a number T (T <= 10) , indicating the number of test cases.
For each test case, the first line is a number N (N <= 105), the number of nodes in the tree.
The second line comes with N numbers v1, v2, v3 ... , vN, describing the value of node 1 to node N. (1 <= vi <= 109)
The third line comes with N - 1 numbers p2, p3, p4 ... , pN, describing
the father nodes of node 2 to node N. Node 1 is the root and will have no father.
Then comes a number Q, it is the number of queries. (Q <= 105)
For next Q lines, each with two numbers u and v. As described above.
[align=left]Output[/align]
For test case X, output "Case #X:" at the first line.
Then output Q lines, each with an answer to the query.
There should be a blank line *BETWEEN* each test case.
[align=left]Sample Input[/align]
[align=left]Sample Output[/align]
[align=left]Source[/align]
2013 ACM/ICPC Asia Regional Online —— Warmup2
题意:给定一个节点数小于10w的树,每个节点有一个点权。再给出Q次询问(小于10w),每次给定一个起点和终点u,v。求在u点到v点的最短路上,节点点权的最长上连续升子段的长度。
思路:
除了数链剖分,动态树等方法之外,此题还可采用树上路径倍增的方法来解决。分别维护以某个节点,往上走2^i步之后的区间内的一些信息。这里,假设这个区间是有方向的,就是以上述的“某个”节点为起点,以上述的”往上走2^i步之后“到达的点为终点。用LL[0],LL[1]分别表示这个区间从起点(定义为左端点)开始最长连续的上升、下降子段长度,RR[0]、RR[1]表示终点为区间右端点的最长的连续上升、下降的子段长度。用ans[0]、ans[1]分别维护这个区间内连续上升、下降的长度。特别注意,这里说的上升下降,是在规定了区间起点和终点的情况下说的!
对于每一次询问,先求出u,v的lca。lca也用树上路径倍增的方法来维护和求得。维护的到u-lca段上的右连续上升和这个区间内的最长连续上升段的长度,维护得到v-lca的右连续下降长度和这个区间内的最长下降段的长度。对于lca-v这区间,颠倒起点终点之后,维护的值都代表上升的长度啦!最后答案就是u-lca的答案,v-lca的答案,两个右连续的和,这三个值取最大值。
这个方法,效率挺高的。
The LCIS on the Tree
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)[align=left]Problem Description[/align]
For a sequence S1, S2, ... , SN, and a pair of integers (i, j), if 1 <= i <= j <= N and Si
< Si+1 < Si+2 < ... < Sj-1 < Sj , then the sequence Si,
Si+1, ... , Sj is aCIS (Continuous Increasing Subsequence). The longestCIS of a sequence is called theLCIS (Longest
Continuous Increasing Subsequence).
Now we consider a tree rooted at node 1. Nodes have values. We have Q queries, each with two nodes u and v. You have to find the shortest path from u to v. And write down each nodes' value on the path, from u to v, inclusive. Then you will get a sequence, and
please show us the length of its LCIS.
[align=left]Input[/align]
The first line has a number T (T <= 10) , indicating the number of test cases.
For each test case, the first line is a number N (N <= 105), the number of nodes in the tree.
The second line comes with N numbers v1, v2, v3 ... , vN, describing the value of node 1 to node N. (1 <= vi <= 109)
The third line comes with N - 1 numbers p2, p3, p4 ... , pN, describing
the father nodes of node 2 to node N. Node 1 is the root and will have no father.
Then comes a number Q, it is the number of queries. (Q <= 105)
For next Q lines, each with two numbers u and v. As described above.
[align=left]Output[/align]
For test case X, output "Case #X:" at the first line.
Then output Q lines, each with an answer to the query.
There should be a blank line *BETWEEN* each test case.
[align=left]Sample Input[/align]
1 5 1 2 3 4 5 1 1 3 3 3 1 5 4 5 2 5
[align=left]Sample Output[/align]
Case #1: 3 2 3
[align=left]Source[/align]
2013 ACM/ICPC Asia Regional Online —— Warmup2
题意:给定一个节点数小于10w的树,每个节点有一个点权。再给出Q次询问(小于10w),每次给定一个起点和终点u,v。求在u点到v点的最短路上,节点点权的最长上连续升子段的长度。
思路:
除了数链剖分,动态树等方法之外,此题还可采用树上路径倍增的方法来解决。分别维护以某个节点,往上走2^i步之后的区间内的一些信息。这里,假设这个区间是有方向的,就是以上述的“某个”节点为起点,以上述的”往上走2^i步之后“到达的点为终点。用LL[0],LL[1]分别表示这个区间从起点(定义为左端点)开始最长连续的上升、下降子段长度,RR[0]、RR[1]表示终点为区间右端点的最长的连续上升、下降的子段长度。用ans[0]、ans[1]分别维护这个区间内连续上升、下降的长度。特别注意,这里说的上升下降,是在规定了区间起点和终点的情况下说的!
对于每一次询问,先求出u,v的lca。lca也用树上路径倍增的方法来维护和求得。维护的到u-lca段上的右连续上升和这个区间内的最长连续上升段的长度,维护得到v-lca的右连续下降长度和这个区间内的最长下降段的长度。对于lca-v这区间,颠倒起点终点之后,维护的值都代表上升的长度啦!最后答案就是u-lca的答案,v-lca的答案,两个右连续的和,这三个值取最大值。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 100005 int anc[MAXN][17]; int LL[MAXN][17][2], RR[MAXN][17][2]; int ans[MAXN][17][2]; int dep[MAXN]; struct EDGE { EDGE() {} EDGE(int _to, int _next) { to = _to, next = _next; } int to, next; }edge[MAXN]; int edgecnt, head[MAXN]; void init() { memset(anc, -1, sizeof(anc)); memset(head, -1, sizeof(head)); edgecnt = 0; } void add(int s, int t) { edge[edgecnt] = EDGE(t, head[s]); head[s] = edgecnt++; } int val[MAXN]; void dfs(int u, int fa, int deep) { anc[u][0] = fa; dep[u] = deep; if (val[u] < val[fa]) { LL[u][0][0] = 2; LL[u][0][1] = 1; RR[u][0][0] = 2; RR[u][0][1] = 1; ans[u][0][0] = 2; ans[u][0][1] = 1; } else if (val[u]>val[fa]) { LL[u][0][0] = 1; LL[u][0][1] = 2; RR[u][0][0] = 1; RR[u][0][1] = 2; ans[u][0][0] = 1; ans[u][0][1] = 2; } else { LL[u][0][0] = LL[u][0][1] = RR[u][0][0] = RR[u][0][1] = ans[u][0][0] = ans[u][0][1] = 1; } for (int i = head[u]; ~i; i = edge[i].next) dfs(edge[i].to, u, deep + 1); } void process(int n) { for (int j = 0; j < 16; j++) for (int i = 1; i <= n; i++) { if (dep[anc[i][j]]>(1 << j)) { anc[i][j + 1] = anc[anc[i][j]][j]; int A = anc[i][j]; int len = (1 << j) + 1; if (LL[i][j][0] == len) LL[i][j + 1][0] = len - 1 + LL[A][j][0]; else LL[i][j + 1][0] = LL[i][j][0]; if (RR[A][j][0] == len) RR[i][j + 1][0] = len - 1 + RR[i][j][0]; else RR[i][j + 1][0] = RR[A][j][0]; if (LL[i][j][1] == len) LL[i][j + 1][1] = len - 1 + LL[A][j][1]; else LL[i][j + 1][1] = LL[i][j][1]; if (RR[A][j][1] == len) RR[i][j + 1][1] = len - 1 + RR[i][j][1]; else RR[i][j + 1][1] = RR[A][j][1]; ans[i][j + 1][0] = max(ans[i][j][0], ans[A][j][0]); ans[i][j + 1][0] = max(ans[i][j + 1][0], RR[i][j][0] + LL[A][j][0] - 1); ans[i][j + 1][1] = max(ans[i][j][1], ans[A][j][1]); ans[i][j + 1][1] = max(ans[i][j + 1][1], RR[i][j][1] + LL[A][j][1] - 1); } } } int lca(int u, int v) { if (dep[u] < dep[v]) swap(u, v); for (int i = 16; i >= 0; i--) if (dep[u] - (1 << i) >= dep[v]) u = anc[u][i]; if (u == v) return u; for (int i = 16; i >= 0; i--) if (anc[u][i] != anc[v][i]) { u = anc[u][i]; v = anc[v][i]; } return anc[u][0]; } int getans(int u, int v) { int l = lca(u, v); int Ru = 1, ansu = 1; bool first = 1; for (int i = 16; i >= 0; i--) if (dep[u] - (1 << i) >= dep[l]) { if (first) { Ru = RR[u][i][0]; ansu = ans[u][i][0]; first = 0; u = anc[u][i]; continue; } ansu = max(ansu, ans[u][i][0]); ansu = max(ansu, Ru + LL[u][i][0] - 1); int len = (1 << i) + 1; if (len == RR[u][i][0]) Ru += RR[u][i][0] - 1; else Ru = RR[u][i][0]; u = anc[u][i]; } int Rv = 1, ansv = 1; first = 1; for (int i = 16; i >= 0; i--) if (dep[v] - (1 << i) >= dep[l]) { if (first) { Rv = RR[v][i][1]; ansv = ans[v][i][1]; first = 0; v = anc[v][i]; continue; } ansv = max(ansv, ans[v][i][1]); ansv = max(ansv, Rv + LL[v][i][1] - 1); int len = (1 << i) + 1; if (len == RR[v][i][1]) Rv += RR[v][i][1] - 1; else Rv = RR[v][i][1]; v = anc[v][i]; } int ans = max(ansu, ansv); ans = max(ans, Ru + Rv - 1); return ans; } int main() { int T; int ks = 0; scanf("%d", &T); bool ok = 0; while (T--) { if (ok != 0) { puts(""); } ok = 1; printf("Case #%d:\n", ++ks); int n; scanf("%d", &n); init(); for (int i = 1; i <= n; i++) scanf("%d", &val[i]); for (int i = 2; i <= n; i++) { int s; scanf("%d", &s); add(s, i); } dfs(1, -1, 1); process(n); int Q; scanf("%d", &Q); while (Q--) { int u, v; scanf("%d %d", &u, &v); printf("%d\n", getans(u, v)); } } return 0; }
这个方法,效率挺高的。
相关文章推荐
- JavaScript的加载和运行
- new/delete和malloc/free的区别
- Redis常用命令——string
- Oracle 统计数据库 表的个数和名字
- JAVAWEB 生成excel文字在一格显示两位不变成#号
- openstack 安装
- 分布式与集群的区别
- HDU 1597 find the nth digit
- CodeForces 1B-Spreadsheet
- 博弈论
- Java NIO框架Netty教程 (九)-再谈收发信息次数问题
- 南邮 OJ 1142 最大连续和
- Lua的字符串分割函数
- C#(WPF)中使用WinAPI函数进行截屏
- MySQL 5.6 for Windows 解压缩版配置安装
- 一只程序员的自述
- 与Python触电
- 追MM与设计模式(23种设计模式巧妙解析,趣味理解)
- C#(WPF)中使用WinAPI函数进行截屏
- UVa 1354 枚举子集 Mobile Computing