分析
首先,此题需要加点和查询操作
我们可以想到倍增
但由于对于祖先的选择有要求
所以我们需要修改对于倍增数组的表示Anc[i][j]表示从点向上走
个满足要求的点之后,到达的点
Sum[i][j]表示从点向上走
个满足要求的点得权值之和
这样我们就可以查询了
至于插入操作
我们需要先求出此点祖先中第一个满足要求的祖先
我们也可以直接得到
时间复杂度:
代码
//CF932D
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define LL long long
#define Lowbit(X) (X&(-X))
#define Lson (X<<1)
#define Rson (X<<1|1)
#define Cl(X,Y) memset((X),(Y),sizeof(X))
#define FOR(i,A,B) for(LL i=A;i<=B;i++)
#define BOR(i,A,B) for(LL i=A;i>=B;i--)
#define FOR_SIDE(i,A) for(LL i=Head[A];i;i=Next[i])
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const LL MAXN=4e5+10;
LL Size=1,Total,Opt,u,v,w,Test,Last;
LL Num[MAXN];
LL Anc[MAXN][21],Sum[MAXN][21];
inline void File() {
freopen(".in","r",stdin);
freopen(".out","w",stdout);
}
inline void Update(LL New,LL Pre) {
if(Num[Pre]>=Num[New]) Anc[New][0]=Pre,Sum[New][0]=Num[Anc[New][0]];
else {
BOR(i,20,0) if(Num[Anc[Pre][i]]<Num[New]) Pre=Anc[Pre][i];
Anc[New][0]=Anc[Pre][0];
Sum[New][0]=Num[Anc[New][0]];
}
FOR(i,1,20) {
Anc[New][i]=Anc[Anc[New][i-1]][i-1];
if(Sum[New][i-1]==INF) Sum[New][i]=INF;
else Sum[New][i]=Sum[New][i-1]+Sum[Anc[New][i-1]][i-1];
}
}
inline LL Get(LL New,LL Limit) {
if(Num[New]>Limit) return (LL)0;
Limit-=Num[New];
LL Res=0;
BOR(i,20,0)
if(Sum[New][i]<=Limit) { Limit-=Sum[New][i]; New=Anc[New][i]; Res+=(1<<i); }
return Res+1;
}
signed main() {
//File();
scanf("%lld",&Test);
Num[0]=INF;
Cl(Sum[1],0x3f);
while(Test--) {
scanf("%lld %lld %lld",&Opt,&u,&v);
u^=Last; v^=Last;
if(Opt==1) Num[++Size]=v,Update(Size,u);
else printf("%lld\n",Last=Get(u,v));
}
//fclose(stdin); fclose(stdout);
system("pause");
return 0;
} 
京公网安备 11010502036488号