HDU 4718 The LCIS on the Tree(树链剖分)

Problem Description

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
CIS(Continuous Increasing Subsequence). The
longest CIS of a sequence is called
the LCIS (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.

Input

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.

Output

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.

题目大意:给你一棵树,每个点上有一个权值,Q个询问,问u到v的最短路径上的点权都取出来排成一排,这一段的LCIS是多少(最长连续上升子序列)。

思路:还算是比较裸的树链剖分,每条链用一个线段树来维护,不过要同时维护太多的东西难度有点高……反正不会有修改操作,果断把从某个点开始的LCIS等等改成了预处理……反正就是相当的麻烦……手欠开了一条麻烦得要死的题目……

代码(2062MS):

  1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 using namespace std;
6
7 const int MAXV = 100010;
8 const int MAXE = MAXV;
9 const int MAXT = MAXV << 2;
10
11 int lmaxi[MAXT], rmaxi[MAXT], mmaxi[MAXT];
12 int lmaxd[MAXT], rmaxd[MAXT], mmaxd[MAXT];
13 int val[MAXV], n, m, T;
14
15 int inc_ord[MAXV], dec_ord[MAXV], inc_rev[MAXV], dec_rev[MAXV];
16
17 void init_inc_dec() {
18 for(int i = 1, t = 1; i <= n; ++i) {
19 if(t < i) t = i;
20 while(t < n && val[t] < val[t + 1]) ++t;
21 inc_ord[i] = t - i + 1;
22 }
23 for(int i = 1, t = 1; i <= n; ++i) {
24 if(t < i) t = i;
25 while(t < n && val[t] > val[t + 1]) ++t;
26 dec_ord[i] = t - i + 1;
27 }
28 for(int i = n, t = n; i > 0; --i) {
29 if(t > i) t = i;
30 while(t > 0 && val[t] < val[t - 1]) --t;
31 inc_rev[i] = i - t + 1;
32 }
33 for(int i = n, t = n; i > 0; --i) {
34 if(t > i) t = i;
35 while(t > 0 && val[t] > val[t - 1]) --t;
36 dec_rev[i] = i - t + 1;
37 }
38 }
39
40 int queryI(int x, int l, int r, int a, int b) {
41 if(a <= l && r <= b) {
42 return mmaxi[x];
43 } else {
44 int ll = x << 1, rr = ll | 1, mid = (l + r) >> 1;
45 int ans = 0;
46 if(a <= mid) ans = max(ans, queryI(ll, l, mid, a, b));
47 if(mid < b) ans = max(ans, queryI(rr, mid + 1, r, a, b));
48 if(val[mid] < val[mid + 1]) {
49 ans = max(ans, min(rmaxi[ll], mid - a + 1) + min(lmaxi[rr], b - mid));
50 }
51 return ans;
52 }
53 }
54
55 int queryD(int x, int l, int r, int a, int b) {
56 if(a <= l && r <= b) {
57 return mmaxd[x];
58 } else {
59 int ll = x << 1, rr = ll | 1, mid = (l + r) >> 1;
60 int ans = 0;
61 if(a <= mid) ans = max(ans, queryD(ll, l, mid, a, b));
62 if(mid < b) ans = max(ans, queryD(rr, mid + 1, r, a, b));
63 if(val[mid] > val[mid + 1]) {
64 ans = max(ans, min(rmaxd[ll], mid - a + 1) + min(lmaxd[rr], b - mid));
65 }
66 return ans;
67 }
68 }
69
70 void maintainI(int x, int l, int r) {
71 int ll = x << 1, rr = ll | 1, mid = (l + r) >> 1;
72 if(val[mid] < val[mid + 1]) {
73 lmaxi[x] = lmaxi[ll] + (lmaxi[ll] == mid - l + 1) * lmaxi[rr];
74 rmaxi[x] = rmaxi[rr] + (rmaxi[rr] == r - mid) * rmaxi[ll];
75 mmaxi[x] = max(rmaxi[ll] + lmaxi[rr], max(mmaxi[ll], mmaxi[rr]));
76 } else {
77 lmaxi[x] = lmaxi[ll];
78 rmaxi[x] = rmaxi[rr];
79 mmaxi[x] = max(mmaxi[ll], mmaxi[rr]);
80 }
81 }
82
83 void maintainD(int x, int l, int r) {
84 int ll = x << 1, rr = ll | 1, mid = (l + r) >> 1;
85 if(val[mid] > val[mid + 1]) {
86 lmaxd[x] = lmaxd[ll] + (lmaxd[ll] == mid - l + 1) * lmaxd[rr];
87 rmaxd[x] = rmaxd[rr] + (rmaxd[rr] == r - mid) * rmaxd[ll];
88 mmaxd[x] = max(rmaxd[ll] + lmaxd[rr], max(mmaxd[ll], mmaxd[rr]));
89 } else {
90 lmaxd[x] = lmaxd[ll];
91 rmaxd[x] = rmaxd[rr];
92 mmaxd[x] = max(mmaxd[ll], mmaxd[rr]);
93 }
94 }
95
96 void build(int x, int l, int r) {
97 if(l == r) {
98 lmaxi[x] = rmaxi[x] = mmaxi[x] = 1;
99 lmaxd[x] = rmaxd[x] = mmaxd[x] = 1;
100 } else {
101 int ll = x << 1, rr = ll | 1, mid = (l + r) >> 1;
102 build(ll, l, mid);
103 build(rr, mid + 1, r);
104 maintainI(x, l, r);
105 maintainD(x, l, r);
106 }
107 }
108
109 int v[MAXV];
110 int fa[MAXV], son[MAXV], size[MAXV], tid[MAXV], top[MAXV], dep[MAXV];
111 int head[MAXV], ecnt, dfs_clock;
112 int to[MAXE], next[MAXE];
113
114 void init(int n) {
115 memset(head, -1, (n + 1) * sizeof(int));
116 ecnt = dfs_clock = 0;
117 }
118
119 void add_edge(int u, int v) {
120 to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
121 }
122
123 void dfs_size(int u, int depth) {
124 size[u] = 1; son[u] = 0; dep[u] = depth;
125 int maxsize = 0;
126 for(int p = head[u]; ~p; p = next[p]) {
127 int &v = to[p];
128 dfs_size(v, depth + 1);
129 size[u] += size[v];
130 if(size[v] > maxsize) {
131 son[u] = v;
132 maxsize = size[v];
133 }
134 }
135 }
136
137 void dfs_heavy_edge(int u, int ancestor) {
138 val[tid[u] = ++dfs_clock] = v[u];
139 top[u] = ancestor;
140 if(son[u]) dfs_heavy_edge(son[u], ancestor);
141 for(int p = head[u]; ~p; p = next[p]) {
142 int &v = to[p];
143 if(v == son[u]) continue;
144 dfs_heavy_edge(v, v);
145 }
146 }
147
148 int query(int x, int y) {
149 int res = 0, maxx = 0, prex = 0, maxy = 0, prey = 0;
150 while(top[x] != top[y]) {
151 if(dep[top[x]] > dep[top[y]]) {
152 int sz = dep[x] - dep[top[x]] + 1;
153 int up_ans = min(inc_rev[tid[x]], sz);
154 int down_ans = min(dec_ord[tid[top[x]]], sz);
155 res = max(res, queryD(1, 1, n, tid[top[x]], tid[x]));
156 if(prex && v[prex] >= v[x]) maxx = 0;
157 res = max(res, up_ans + maxx);
158 maxx = down_ans + (sz == down_ans) * maxx;
159 prex = top[x];
160 x = fa[top[x]];
161 } else {
162 int sz = dep[y] - dep[top[y]] + 1;
163 int up_ans = min(dec_rev[tid[y]], sz);
164 int down_ans = min(inc_ord[tid[top[y]]], sz);
165 res = max(res, queryI(1, 1, n, tid[top[y]], tid[y]));
166 if(prey && v[prey] <= v[y]) maxy = 0;
167 res = max(res, up_ans + maxy);
168 maxy = down_ans + (sz == down_ans) * maxy;
169 prey = top[y];
170 y = fa[top[y]];
171 }
172 }
173 if(dep[x] > dep[y]) {
174 int sz = dep[x] - dep[y] + 1;
175 int up_ans = min(inc_rev[tid[x]], sz);
176 int down_ans = min(dec_ord[tid[y]], sz);
177 res = max(res, queryD(1, 1, n, tid[y], tid[x]));
178 if(prex && v[prex] >= v[x]) maxx = 0;
179 if(prey && v[prey] <= v[y]) maxy = 0;
180 res = max(res, up_ans + maxx);
181 res = max(res, down_ans + maxy);
182 if(up_ans == sz) res = max(res, maxx + up_ans + maxy);
183 } else {
184 int sz = dep[y] - dep[x] + 1;
185 int up_ans = min(dec_rev[tid[y]], sz);
186 int down_ans = min(inc_ord[tid[x]], sz);
187 res = max(res, queryI(1, 1, n, tid[x], tid[y]));
188 if(prex && v[prex] >= v[x]) maxx = 0;
189 if(prey && v[prey] <= v[y]) maxy = 0;
190 res = max(res, down_ans + maxx);
191 res = max(res, up_ans + maxy);
192 if(up_ans == sz) res = max(res, maxx + up_ans + maxy);
193 }
194 return res;
195 }
196
197 int main() {
198 scanf("%d", &T);
199 for(int t = 1; t <= T; ++t) {
200 scanf("%d", &n);
201 init(n);
202 for(int i = 1; i <= n; ++i) scanf("%d", &v[i]);
203 for(int i = 2; i <= n; ++i) {
204 scanf("%d", &fa[i]);
205 add_edge(fa[i], i);
206 }
207 dfs_size(1, 1);
208 dfs_heavy_edge(1, 1);
209 build(1, 1, n);
210 init_inc_dec();
211 printf("Case #%d:\n", t);
212 scanf("%d", &m);
213 while(m--) {
214 int u, v;
215 scanf("%d%d", &u, &v);
216 printf("%d\n", query(u, v));
217 }
218 if(t != T) puts("");
219 }
220 }

HDU 4718 The LCIS on the Tree(树链剖分),布布扣,bubuko.com

时间: 2024-12-18 22:40:27

HDU 4718 The LCIS on the Tree(树链剖分)的相关文章

SPOJ375 Query on a tree 树链剖分

SPOJ375  Query on a tree   树链剖分 no tags You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of

SPOJ - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu

hdu 4718 The LCIS on the Tree

题意给你q次询问,给一条链问从给定起点到给定终点的最长连续严格递增子序列. 因为给定起点与终点所以路径可能与dfs序的树节点展开顺序相反.所以问题变成了给n个数询问一个区间的最长LCIS. 但因为方向可正可负,所以我们除了维护区间的最长递增以外还要维护最长递减.线段树的部分就做完了. 树链剖分的时候进行线段树合并,合并的时候右区间取前一个区间,左区间取当前区间.要注意从起点出发的链取最长递减,从终点出发的取最长递增. 当他们来到一条链时,当x比y 的深度更浅这时应该将这段长度与y合并,y比x浅时

hdu 4912 Paths on the tree(树链剖分+贪心)

题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道,要求尽量选出多的通道,并且两两通道不想交. 解题思路:用树链剖分求LCA,然后根据通道两端节点的LCA深度排序,从深度最大优先选,判断两个节点均没被标 记即为可选通道.每次选完通道,将该通道LCA以下点全部标记. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include

HDU 5044 Tree 树链剖分

一棵树,初始边权和点权都为0 现在有m个操作,每一个操作: ADD1 u v k: for nodes on the path from u to v, the value of these nodes increase by k. ADD2 u v k: for edges on the path from u to v, the value of these edges increase by k. 操作完后,输出每一个点的点权和每一条边的边权(边权按照输入顺序输出) 我们把边权也当做点权处

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

spoj 375 Query on a tree (树链剖分)

Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to ti or Q

HDU 3966 Aragorn&amp;#39;s Story(树链剖分)

HDU Aragorn's Story 题目链接 树抛入门裸题,这题是区间改动单点查询,于是套树状数组就OK了 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 50005; inline int lowbit(int x) {return x&(-x);} int dep

SPOJ Query on a tree 树链剖分 水题

You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to tior QUERY a b : ask fo