codeforces.ml/contest/932/problem/D 树上找最长上升子序列长度 倍增算法

D. Tree
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

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
    1. starts with R.
    2. Every node in the sequence is an ancestor of its predecessor.
    3. Sum of weight of nodes in sequence does not exceed X.
    4. 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.

Input

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

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;
        }
    }
}

 

 

 

posted @ 2022-09-05 16:36  er007  阅读(25)  评论(0编辑  收藏  举报