【题意】
共Q个操作,每个操作1加入一个权重为w的点在点r下头。
操作2询问对于一个点r,以它和它祖先组成权重和不超过x的最长不下降子序列,满足序列长度最大,对其中每个相邻的i,j,若满足j是i的祖先,则w[j]>=w[i],且i,j中没有k使得w[k]>=w[i]。
(1<=Q<=400000)
【题解】
发现对于新加入的一个节点,祖先中权重小于它的都莫得用,所以可以插入时直接将他插入祖先中第一个大于等于它的节点下,倍增维护它上头的父亲,前缀和。
查询时直接倍增查询前缀和小于x的最后一个点即可。
代码如下:
#include<bits/stdc++.h> #define int long long using namespace std; const int N=4e5+5; const int inf=10000000000000000; int q,last,we[N],f[N][20],sum[N],cnt=2; inline int read() { int x=0,f=1; char c=getchar(); while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();} while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();} return x*f; } signed main() { q=read();we[1]=inf;sum[1]=inf; f[2][0]=1;sum[2]=inf; for(int i=1,x,y,z;i<=q;i++) { x=read();y=read();z=read(); y^=last;z^=last; if(x==1) { y++; if(we[y]>=z) { f[++cnt][0]=y;we[cnt]=z; sum[cnt]=sum[f[cnt][0]]+z; } else { for(int j=19;j>=0;j--) if(f[y][j]&&we[f[y][j]]<z) y=f[y][j]; f[++cnt][0]=f[y][0]; we[cnt]=z; sum[cnt]=sum[f[cnt][0]]+z; } for(int j=1;j<=19;j++) f[cnt][j]=f[f[cnt][j-1]][j-1]; } else { int ans=0,hu=y+1;y++; for(int j=19;j>=0;j--) if(f[y][j]&&sum[hu]-sum[f[y][j]]<=z) y=f[y][j],ans+=1<<j; cout<<ans<<" "; last=ans; } } }