codeforces.ml/contest/932/problem/D 树上找最长上升子序列长度 倍增算法
You are given a node of the tree with index 1 and with weight 0. Let cnt be the number of nodes in the tree at any instant (initially, cnt is set to 1). Support Q queries of following two types:
- Add a new node (index cnt + 1) with weight W and add edge between node R and this node.
- Output the maximum length of sequence of nodes which
- starts with R.
- Every node in the sequence is an ancestor of its predecessor.
- Sum of weight of nodes in sequence does not exceed X.
- For some nodes i, j that are consecutive in the sequence if i is an ancestor of j then w[i] ≥ w[j] and there should not exist a node k on simple path from i to j such that w[k] ≥ w[j]
The tree is rooted at node 1 at any instant.
Note that the queries are given in a modified way.
First line containing the number of queries Q (1 ≤ Q ≤ 400000).
Let last be the answer for previous query of type 2 (initially last equals 0).
Each of the next Q lines contains a query of following form:
- 1 p q (1 ≤ p, q ≤ 1018): This is query of first type where and . It is guaranteed that 1 ≤ R ≤ cnt and 0 ≤ W ≤ 109.
- 2 p q (1 ≤ p, q ≤ 1018): This is query of second type where and . It is guaranteed that 1 ≤ R ≤ cnt and 0 ≤ X ≤ 1015.
denotes bitwise XOR of a and b.
It is guaranteed that at least one query of type 2 exists.
Output the answer to each query of second type in separate line.
题意:
初始有个1号点,权值为0
操作1,将编号为cnt +1的点加到R号点后面,权值为W
操作2,查询编号为 R 的点,往祖宗节点上走,最大上升子序列的长度
分析:
树上操作,数据范围是1e18,考虑倍增。2^18 = 1e18
操作1:假设当前点是cnt,接在 R 后面,权值为 W,可以考虑维护 w[N][20] ,w[cnt][0] 表示 比 cnt大的第一个节点,就可以倍增去找比当前节点大的第一个节点,并接在它后面,它后面的节点都是比它大的。
操作2:维护 g[N][20] 表示,这个节点往上 2^j 个节点的权值总和,可以倍增找到 最大的上升子序列长度
#define int ll const int N = 4e5+10; int n,m,q; int V[N],g[N][20],f[N][20],fa[N],dep[N]; void add(int cnt,int r,ll w) { fa[cnt] = r;f[cnt][0] = r;g[cnt][0] = w; V[cnt] = w;dep[cnt] = dep[r] + 1; for(int j = 1;j <= 19;j ++ ) { f[cnt][j] = f[f[cnt][j-1]][j-1]; g[cnt][j] = g[cnt][j-1] + g[f[cnt][j-1]][j-1]; } } int find(int r,ll w) { return !r || V[r] >= w ? r : find(fa[r],w); } void solve() { // cin>>n>>m; cin>>q; int la = 0,cnt = 1; dep[1] = 1; while(q -- ) { int op;cin>>op;; if(op == 1) { int r,w;cin>>r>>w; r = r ^ la, w = w ^ la; add(++ cnt,find(r,w),w); } else { ll ans = 0; int r,x;cin>>r>>x; r = r ^ la,x = x ^ la; for(int j = 19;j >= 0 ;j -- ) { if(g[r][j] <= x) { x -= g[r][j]; ans += min(1ll * (1<<j),dep[r]); r = f[r][j]; } } cout<<(la = ans)<<endl; } } }