CF932D-Tree【倍增法】

题目链接:传送门

D. Tree

time limit per test2 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard 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 c n t   +   1 cnt + 1 cnt+1) with weight W W W and add edge between node R R 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 X X.
For some nodes i ,   j i, j i,j that are consecutive in the sequence if i is an ancestor of j then w [ i ]   ≥   w [ j ] w[i] ≥ w[j] w[i]w[j] and there should not exist a node k k k on simple path from i i i to j j j such that w [ k ]   ≥   w [ j ] w[k] ≥ w[j] 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 Q Q ( 1   ≤   Q   ≤   400000 1 ≤ Q ≤ 400000 1Q400000).

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 1 1 p p p q ( 1   ≤   p ,   q   ≤   1 0 18 ) : q (1 ≤ p, q ≤ 10^{18}): q(1p,q1018): This is query of first type where and . It is guaranteed that 1   ≤   R   ≤   c n t 1 ≤ R ≤ cnt 1Rcnt and 0   ≤   W   ≤   1 0 9 0 ≤ W ≤ 10^9 0W109.
2 2 2 p p p q q q ( 1   ≤   p ,   q   ≤   1 0 18 1 ≤ p, q ≤ 10^{18} 1p,q1018): This is query of second type where and . It is guaranteed that 1   ≤   R   ≤   c n t 1 ≤ R ≤ cnt 1Rcnt and 0   ≤   X   ≤   1 0 15 0 ≤ X ≤ 10^{15} 0X1015.
denotes bitwise X O R XOR XOR of a a a and b b 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.

Examples

input
6
1 1 1
2 2 0
2 2 1
1 3 0
2 2 0
2 2 2
output
0
1
1
2
input
6
1 1 0
2 2 0
2 0 3
1 0 2
2 1 3
2 1 6
output
2
2
3
2
input
7
1 1 2
1 2 3
2 3 3
1 0 0
1 5 1
2 5 0
2 4 0
output
1
1
2
input
7
1 1 3
1 2 3
2 3 4
1 2 0
1 5 3
2 5 5
2 7 22
output
1
2
3

Note

In the first example,

l a s t   =   0 last = 0 last=0

  • Query 1: 1 1 1, Node 2 with weight 1 is added to node 1.

  • Query 2: 2 2 0, No sequence of nodes starting at 2 has weight less than or equal to 0. l a s t   =   0 last = 0 last=0

  • Query 3: 2 2 1, Answer is 1 as sequence will be {2}. l a s t   =   1 last = 1 last=1

  • Query 4: 1 2 1, Node 3 with weight 1 is added to node 2.

  • Query 5: 2 3 1, Answer is 1 as sequence will be {3}. Node 2 cannot be added as sum of weights cannot be greater than 1. l a s t   =   1 last = 1 last=1

  • Query 6: 2 3 3, Answer is 2 as sequence will be {3, 2}. l a s t   =   2 last = 2 last=2

题意

给一颗树,每个点都有一个权值,两种操作,一个是在某个节点添加一个儿子节点,另一种是询问一个从 c u r cur cur开始的最长的序列 W W W(用节点表示),记这个序列长度为 l e n len len,这个序列满足如下要求:
  • W [ j ] W[j] W[j] W [ i ] W[i] W[i]的一个祖先对任意的 i , j ( j > i ) i,j(j>i) i,j(j>i)成立
  • ∑ i = 1 i = l e n v a l [ W [ i ] ] &lt; = X \sum_{i=1}^{i=len}{val[W[i]]}&lt;=X i=1i=lenval[W[i]]<=X
  • ∀ i &lt; l e n \forall i&lt;len i<len v a l [ W [ i + 1 ] ] &gt; = v a l [ W [ i ] ] val[W[i+1]]&gt;=val[W[i]] val[W[i+1]]>=val[W[i]]从节点 W [ i ] W[i] W[i]路径到 W [ i + 1 ] W[i+1] W[i+1]的简单路径上的权值均小于 v a l [ W [ i ] ] val[W[i]] val[W[i]]

题解:倍增法

可以看出,只需在从 c u r cur cur节点到根节点的简单路径经过的节点中,如果当前节点权值大于等于前一个节点权值,那么这个节点可以取且必须取(不取将不满足第三个要求),然后一直取知道权值大于 X X X或到了根节点。
那么可以用 d p [ c u r ] [ i ] dp[cur][i] dp[cur][i]表示从 c u r cur cur开始的第 2 i 2^i 2i个节点( c u r cur cur不算在内),然后先考虑状态转移:
  • 首先找到从 c u r cur cur到根节点的简单路径上的第一个大于 v a l [ c u r ] val[cur] val[cur]的节点
  • 然后将该节点的状态转移到 c u r cur cur节点上

附代码:

#include<bits/stdc++.h>

using namespace std;
const int maxn = 400005;
typedef long long ll;

ll u, w, cnt = 0, x, pre[maxn][21], val[maxn], sum[maxn][21];
ll ans = 0;
int type, m;

int main()
{
    scanf("%d", &m);
    val[++cnt] = 0;
    for(int i = 0; i <= 20; i++) sum[1][i] = 1e18;
    val[0] = 1e18;
    for(int i = 1; i <= m; i++)
    {
        scanf("%d %lld %lld", &type, &u, &x);
        u ^= ans;
        x ^= ans;
        if(type == 1)
        {
            cnt++;
            val[cnt] = x;
            if(val[u] >= x) pre[cnt][0] = u;
            else
            {
                for(int i = 20; i >= 0; i--)
                {
                    if(val[pre[u][i]] < x)
                    {
                        u = pre[u][i];
                    }
                }
                pre[cnt][0] = pre[u][0];
            }
            sum[cnt][0] = !pre[cnt][0] ? 1e18 : val[pre[cnt][0]];
            for(int i = 1; i <= 20; i++)
            {
                pre[cnt][i] = pre[pre[cnt][i - 1]][i - 1];
                sum[cnt][i] = !pre[cnt][i] ? 1e18 : sum[pre[cnt][i - 1]][i - 1] + sum[cnt][i - 1];
            }


        }
        else
        {
            if(x < val[u])
            {
                printf("0\n");
                ans = 0ll;
                continue;
            }
            ans = 1ll;
            x -= val[u];
            for(int i = 20; i >= 0; i--)
            {
                if(sum[u][i] <= x)
                {
                    x -= sum[u][i];
                    ans += (1 << i);
                    u = pre[u][i];
                }
            }
            printf("%lld\n", ans);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值