Codeforces 932D - Tree 【树上倍增】


D. Tree

time limit per test  2seconds

memory limit per test      512megabytes


You are given a node of the tree withindex 1 and with weight 0. Let cnt be the numberof nodes in the tree at any instant (initially, cnt is set to 1). Support Q queries offollowing two types:

·  Add a new node (index cnt + 1) with weight W and add edgebetween 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 itspredecessor.

3.    Sum of weight of nodes in sequence does not exceed X.

4.    For some nodes i, j that areconsecutive in the sequence if i is an ancestorof j then w[i] ≥ w[j] and thereshould 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 thequeries are given in a modified way.

Input

First line containing the number ofqueries Q (1 ≤ Q ≤ 400000).

Let last be the answerfor previous query of type 2 (initially last equals 0).

Each of the next Q lines containsa query of following form:

·  1 p q (1 ≤ p, q ≤ 1018): This is queryof first type where   and   . It is guaranteed that 1 ≤ R ≤ cnt and 0 ≤ W ≤ 109.

·  2 p q (1 ≤ p, q ≤ 1018): This is queryof 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 queryof type 2 exists.

Output

Output the answer to each query of second type inseparate line.


【题意】


有一棵树,书上每个点都有一个权值,一开始只有根节点,且权值为0。然后有两种操作:


一种是新加上一个节点连在R后面,且权值为W;


第二种是从一个点R开始往祖先走,每次走到第一个权值大于等于自身的节点,问走过的节点权值和不超过X,最多能经过几个点。


【思路】


对于往祖先找符合条件的点,暴力方法便是一个一个往祖先走,但是我们可以用倍增的思想来优化。


我们用fa[u][i]表示权值大于等于u的第2i个祖先,每次加点时先处理出fa[u][0],然后就能根据祖先节点推出fa[u][i]


对于fa[u][0],如何其依附的点R权值大于等于它,那么fa[u][0]即为R,否则我们应该从R开始走,i从大的往小的枚举(走2i步),如果满足w[fa[R][i]] < w[u],说明权值大于u的点还在上面,跳上去更新R代表的点,继续枚举,最后fa[u][0]=fa[R][0];


对于查询操作,我们需要sum[u][i]表示从u点跳2i个点(不包括u)的权值和,然后查询时,先判断总权值X是否大于等于u的权值,是的话X-=w[u],然后同上,i从大的开始枚举如果sum[u][i]<=X就往祖先走,并且X-=sum[u][i],以此类推。



#include <cstdio>
#include <cmath>
#include <set>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

typedef long long ll;
const int maxn = 400005;
const ll mod = 1e9+7;
const ll INF = 1e18;
const double eps = 1e-9;

int q,op,cnt;
ll a,b,last;
ll w[maxn],sum[maxn][25];
int fa[maxn][25];

void add(int u,int val)
{
    w[++cnt]=val;
    if(w[cnt]<=w[u]) fa[cnt][0]=u;
    else
    {
        for(int i=20;i>=0;i--)
        {
            if(w[fa[u][i]]<w[cnt]) u=fa[u][i];
        }
        fa[cnt][0]=fa[u][0];
    }
    if(fa[cnt][0]==0) sum[cnt][0]=INF;
    else sum[cnt][0]=w[fa[cnt][0]];
    for(int i=1;i<=20;i++)
    {
        fa[cnt][i]=fa[fa[cnt][i-1]][i-1];
        if(fa[cnt][i]==0) sum[cnt][i]=INF;
        else sum[cnt][i]=sum[cnt][i-1]+sum[fa[cnt][i-1]][i-1];
    }
}

ll query(int u,ll val)
{
    if(w[u]>val) return 0;
    val-=w[u];
    ll ans=1;
    for(int i=20;i>=0;i--)
    {
        if(val>=sum[u][i])
        {
            val-=sum[u][i];
            ans+=(1<<i);
            u=fa[u][i];
        }
    }
    return ans;
}

int main()
{
    w[0]=INF;
    w[1]=0;
    last=0;
    cnt=1;
    mst(sum[1],0x3f);
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%lld%lld",&op,&a,&b);
        a^=last;
        b^=last;
        if(op==1) add(a,b);
        else printf("%lld\n",last=query(a,b));
    }
}



 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值