题目链接:CodeForce-932D
主要思路:
由于操作是加密给出的,我们不得不在线操作。由于又是在树上的结点顺序遍历(一直向其祖先遍历),故可以使用树上的倍增。这里我们定义每一步都是跳到其离他最近的又权值大于他的结点(可以用在倍增表上二分)。在加入节点时,只用知道他下一步的位置,即可继承他走每步的信息。中间再与fa数组一样开一个数组记录跳过的结点的权值之和。查找时逆序枚举2^i步,只要权值和没有大于X就继续向下跳。最后判断最后一步可不可以调就可以了(其实和LCA上的二分差不多)。若不能理解就先二分打一遍,再在倍增表上二分。
#include<cstdio>
#define M 400005
struct E {
int nx,to;
} edge[M];
int tot=1;
int fa[M][20],dep[M];
long long val[M],cost[M];
void Addedge(int a,long long d) {
fa[++tot][0]=a;
val[tot]=d;
if(val[a]>=d) {
fa[tot][0]=a;
} else {
for(int i=19; i>=0; i--) {//二分跳跃
if(!fa[a][i])continue;//跳出这棵树就不用更新
if(val[fa[a][i]]<d)a=fa[a][i];
}
fa[tot][0]=fa[a][0];
}
dep[tot]=dep[fa[tot][0]]+1;//到后面算跳了几个结点
cost[tot]=cost[fa[tot][0]]+d;//到后面算跳了这几个结点的权值之和,也算是树上的前缀和吧(注意这几个结点在树上并不一定连续)
for(int i=1; i<20; i++)fa[tot][i]=fa[fa[tot][i-1]][i-1];//由fa[tot][0]推出其后的fa数组
}
int Query(int p,long long q) {
int ans=0;
for(int i=19; i>=0; i--) {//二分跳跃
if(!fa[p][i])continue;
if(cost[p]-cost[fa[p][i]]<=q) {//只要跳过的权值之和小于q就跳
ans+=dep[p]-dep[fa[p][i]];
q-=cost[p]-cost[fa[p][i]];
p=fa[p][i];
}
}
if(val[p]<=q)ans++;//最后一步还能不能跳
return ans;
}
int main() {
int Q,last=0;
scanf("%d",&Q);
dep[1]=1;
while(Q--) {
int a;
long long p,q;
scanf("%d%lld%lld",&a,&p,&q);
p=last^p,q=last^q;//解密
if(a==1) {
Addedge(p,q);
} else {
last=Query(p,q);
printf("%d\n",last);
}
}
}