分析
首先,此题需要加点和查询操作
我们可以想到倍增
但由于对于祖先的选择有要求
所以我们需要修改对于倍增数组的表示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; }