• [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
    ",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
    ",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;
    }
  • 相关阅读:
    scala学习笔记1(表达式)
    TDD实践感悟
    Day 21:Docker 入门教程
    人类创造未来的思想先锋:这些 TED 演示深深震撼着我们
    Android开源项目第二篇——工具库篇
    提交表单
    MVC html.beginform & ajax.beginform
    MVC中的传参并在View中获取
    HTTP 教程
    ID和Name
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj3720.html
Copyright © 2020-2023  润新知