n<=400000个在线操作:树上插入一个某点权、父亲为某点的点;查询这样的最长点序列:序列的某个数必须是上一个数的祖先之一;序列的点权和不能超过x;序列的某个点的点权必须不小于上一个,且相邻两个点之间不存在点权大于等于深度大的那个点的点权的点。
说白了,就是每个点找他祖先中第一个点权大于等于他的点,然后建一棵假的树,树边表示某点如果要构造序列,序列的下一个数字就是他祖先。
分别处理:原树父亲、祖先点权最大值、假的树的父亲、假的树的祖先点权和,四个st表一个推一个即可。
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 //#include<map> 6 #include<math.h> 7 //#include<time.h> 8 //#include<complex> 9 #include<algorithm> 10 using namespace std; 11 12 int n; 13 #define maxn 400011 14 #define LL long long 15 LL fa[maxn][22],val[maxn],M[maxn][22],pp[maxn][22],sum[maxn][22],tot=1; 16 17 int main() 18 { 19 scanf("%d",&n); 20 int last=0; LL x,y,z; 21 for (int i=1;i<=n;i++) 22 { 23 scanf("%lld%lld%lld",&x,&y,&z); y^=last; z^=last; 24 if (x==1) 25 { 26 val[++tot]=z; 27 fa[tot][0]=y; for (int i=1;i<=20;i++) fa[tot][i]=fa[fa[tot][i-1]][i-1]; 28 M[tot][0]=max(val[y],z); for (int i=1;i<=20;i++) M[tot][i]=max(M[tot][i-1],M[fa[tot][i-1]][i-1]); 29 if (val[y]>=z) pp[tot][0]=y; 30 else 31 { 32 int t=y; for (int i=20;i>=0;i--) if (fa[t][i] && M[t][i]<z) t=fa[t][i]; t=fa[t][0]; 33 pp[tot][0]=t; 34 } 35 for (int i=1;i<=20;i++) pp[tot][i]=pp[pp[tot][i-1]][i-1]; 36 sum[tot][0]=val[tot]+val[pp[tot][0]]; 37 for (int i=1;i<=20;i++) sum[tot][i]=sum[tot][i-1]+sum[pp[tot][i-1]][i-1]-val[pp[tot][i-1]]; 38 } 39 else 40 { 41 if (val[y]>z) {printf("%d\n",(last=0)); continue;} 42 int t=y,ans=1; for (int i=20;i>=0;i--) if (pp[t][i] && sum[t][i]<=z) ans+=(1<<i),z-=sum[t][i]-val[pp[t][i]],t=pp[t][i]; 43 printf("%d\n",(last=ans)); 44 } 45 } 46 return 0; 47 }