CF932D Tree

【题意】

 

共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<<"\n";
            last=ans;
        }
    } 
}
View Code

猜你喜欢

转载自www.cnblogs.com/betablewaloot/p/12178175.html