[bzoj3720]Gty的妹子树

 来自FallDream的博客,未经允许,请勿转载,谢谢。


题意:给你一棵树,有点权,要求支持三个操作:1)单点修改 2)插入一个点 3)询问子树内权值大于一个数的节点个数。

n,m<=30000

 

去网上搜了一下,发现大家都是块状树啊,还有像带插区间k大那样的替罪羊套treap之类的。但是我写了一个很奇怪的做法 

首先很容易想到主席树之类的,建一次主席树是nlogn的

然后我们把修改操作全部压到一个栈里面,询问的时候把栈遍历一遍计算答案;每当操作到达一定数量的时候,重建整棵树。

假设操作到达k之后重建,复杂度是$O(\frac{n}{k}*nlogn+m(k+logn))$ 

k取到大约$\sqrt{nlogn}$的时候复杂度最小  灰常科学啊

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MN 60000
#define INF 2147483647
#define ll long long
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
struct edge{int to,next;}e[MN*2+5];
struct Tree{int l,r,x;}T[5000000];
struct operation{int kind,x,y,z;}q[MN+5];
int cnt,n,en=0,head[MN+5],last=0,top,nl[MN+5],nr[MN+5],dn=0,m,sz,p[MN+5],a[MN+5],rt[MN+5];
bool b[MN+5];

void ins(int f,int t)
{
    e[++en]=(edge){t,head[f]};head[f]=en;
    e[++en]=(edge){f,head[t]};head[t]=en;
}

void dfs(int x,int f)
{
    p[nl[x]=++dn]=x;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=f) dfs(e[i].to,x);
    nr[x]=dn;
}

void ins(int x,int nx,int k)
{
    int l=0,r=INF,mid;
    while(l<r)
    {
        mid=((ll)l+r)>>1;
        if(k<=mid)
        {
            T[nx].r=T[x].r;T[nx].l=++cnt;
            r=mid;x=T[x].l;nx=T[nx].l;
        }
        else
        {
            T[nx].l=T[x].l;T[nx].r=++cnt;
            l=mid+1;x=T[x].r;nx=T[nx].r;
        }
        T[nx].x=T[x].x+1;
    }
}

int query(int x,int nx,int k)
{
    int sum=0,l=0,r=INF,mid;
    while(l<r)
    {
        mid=((ll)l+r)>>1;
        if(k>mid) x=T[x].r,nx=T[nx].r,l=mid+1;
        else sum+=T[T[nx].r].x-T[T[x].r].x,r=mid,x=T[x].l,nx=T[nx].l;
    }
    return sum+T[nx].x-T[x].x;
}

void build()
{
    dn=cnt=0;dfs(1,0);
    for(int i=1;i<=n;i++)
        ins(rt[i-1],rt[i]=++cnt,a[p[i]]);    
}

int main()
{
    n=read();sz=sqrt(15*n);
    for(int i=1;i<n;i++) ins(read(),read());
    for(int i=1;i<=n;i++) a[i]=read();
    build();m=read();
    for(int i=1,ad=0;i<=m;i++)
    {
        int op=read(),x=read()^last,y=read()^last;
        if(op==0)
        {
            if(x<=n)
            {
                int ans=(y==INF?0:query(rt[nl[x]-1],rt[nr[x]],y+1));
                for(int j=1;j<=top;j++)
                    if(q[j].kind==1)
                    {
                        if(q[j].x<=n&&nl[q[j].x]>=nl[x]&&nl[q[j].x]<=nr[x])
                            ans=ans-(q[j].y>y)+(q[j].z>y);    
                    }
                    else
                    {
                        if((b[q[j].y]&&q[j].y>n)||(q[j].y<=n&&nl[q[j].y]>=nl[x]&&nl[q[j].y]<=nr[x])) b[q[j].x]=1;
                        else b[q[j].x]=0;
                    }
                for(int j=1;j<=ad;j++)
                    if(b[n+j]) ans+=(a[n+j]>y); 
                printf("%d\n",last=ans);
            }
            else
            {
                int ans=0;
                for(int j=1;j<=top;j++)
                    if(q[j].kind==2)
                    {
                        if((b[q[j].y]&&q[j].y>n)||q[j].x==x) b[q[j].x]=1;
                        else b[q[j].x]=0;    
                    } 
                for(int j=1;j<=ad;j++)
                    if(b[n+j]) ans+=(a[n+j]>y);
                printf("%d\n",last=ans);
            }
        }
        else if(op==1) 
            q[++top]=(operation){1,x,a[x],y},a[x]=y;
        else
            q[++top]=(operation){2,n+(++ad),x,0},ins(n+ad,x),a[n+ad]=y;
        if(top>=sz) n+=ad,top=0,ad=0,build();
    }
    return 0;
}

 

posted @ 2017-04-19 10:54  FallDream  阅读(232)  评论(0编辑  收藏  举报