zoukankan      html  css  js  c++  java
  • ZJOI 4573: [Zjoi2016]大森林

    神仙题,不愧是噩梦的ZJOI。

    首先我们发现操作不会改变树的形态,因此可以离线,我们最后从(1)(n)枚举每棵树,考虑两棵树之间的差异并修改

    然后这里维护树的时候涉及了许多变化,因此要用LCT来维护(PS:注意这里的LCT不能换根,因为树是有根的)

    考虑对于增加节点的操作,不难发现对于原来长在([l,r])的节点就算让([1,n])中都长了也不会有影响,因为其它的树里就算长了也是多余的

    但是这样就好了???注意到修改生长节点时我们不能修改没有这个点的树,因此还要记一下这个点实际存在的区间

    然后我们考虑询问,原来查询树上路径的长度时不难的,可是现在的LCT不能split(因为不能makeroot),怎么求两点间距离呢?

    考虑树上差分,两点((x,y))间距离为(dep_x+dep_y-2 imes dep_{operatorname {LCA} (x,y)})

    那么现在我们就要搞出(dep)和求出(operatorname{LCA})

    很显然我们考虑记录每个点子树内点的个数,然后在accesssplay之后以这个点为根的Splay维护的就是根节点到这个点路径上的信息,其实就等价于深度

    然后关于LCA是一个常用的技巧,考虑求(operatorname{LCA}(x,y)),我们先后access(x)access(y),然后不难发现此时(operatorname{LCA}(x,y))就是access(y)时最后操作的节点,具体实现可以看代码

    然后考虑修改,这个操作相当于要把一个点的子树全部嫁接到另一个点上

    据说这个操作可以直接用ETT完成,但显然我是不会这种黑科技的

    那么我们考虑建立虚点,把这个点的所有儿子先往虚点上连,然后要嫁接的时候直接对虚点link,cut即可

    PS:显然虚点不能加入(dep)的计算,因此要把点权赋为(0)

    然后就口胡完了,具体的细节参考代码

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    using namespace std;
    const int N=200005;
    struct event
    {
        int pos,t,x,y;
        inline event(CI P=0,CI T=0,CI X=0,CI Y=0)
        {
            pos=P; t=T; x=X; y=Y;
        }
        inline friend bool operator < (const event& A,const event& B)
        {
            return A.pos<B.pos||(A.pos==B.pos&&A.t<B.t);
        }
    }et[N<<1]; bool isrl[N]; int n,m,opt,l,r,x,cnt_et,cnt_real,cnt_all,cnt_q,lst,ans[N],id[N],L[N],R[N];
    class FileInputOutput
    {
        private:
            static const int S=1<<21;
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
            #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
            char Fin[S],Fout[S],*A,*B; int Ftop,pt[25];
        public:
            Tp inline void read(T& x)
            {
                x=0; char ch; while (!isdigit(ch=tc()));
                while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
            }
            Tp inline void write(T x)
            {
                if (!x) return (void)(pc('0'),pc('
    ')); RI ptop=0;
                while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('
    ');
            }
            inline void Fend(void)
            {
                fwrite(Fout,1,Ftop,stdout);
            }
            #undef tc
            #undef pc
    }F;
    class Link_Cut_Tree
    {
        private:
            struct splay
            {
                int ch[2],fa,size;
            }node[N<<1]; int stack[N<<1],top;
            #define lc(x) node[x].ch[0]
            #define rc(x) node[x].ch[1]
            #define fa(x) node[x].fa
            #define S(x) node[x].size
            inline void pushup(CI now)
            {
                S(now)=S(lc(now))+S(rc(now))+isrl[now];
            }
            inline void connect(CI x,CI y,CI d)
            {
                node[fa(x)=y].ch[d]=x;
            }
            inline int identify(CI now)
            {
                return rc(fa(now))==now;
            }
            inline bool isroot(CI now)
            {
                return lc(fa(now))!=now&&rc(fa(now))!=now;
            }
            inline void rotate(CI now)
            {
                int x=fa(now),y=fa(x),d=identify(now); if (!isroot(x)) node[y].ch[identify(x)]=now;
                fa(now)=y; connect(node[now].ch[d^1],x,d); connect(x,now,d^1); pushup(x);
            }
            inline void splay(int now)
            {
                for (int t;!isroot(now);rotate(now)) t=fa(now),
                !isroot(t)&&(rotate(identify(now)!=identify(t)?now:t),0); pushup(now);
            }
            inline int access(int x,int y=0)
            {
                for (;x;x=fa(y=x)) splay(x),rc(x)=y,pushup(x); return y;
            }
        public:
            inline void link(CI x,CI y)
            {
                splay(x); fa(x)=y;
            }
            inline void cut(CI x)
            {
                access(x); splay(x); lc(x)=fa(lc(x))=0; pushup(x);
            }
            inline int query(CI x,CI y,int ret=0)
            {
                access(x); splay(x); ret=S(x); int fa=access(y); splay(y);
                ret+=S(y); access(fa); splay(fa); return ret-(S(fa)<<1);
            }
            #undef lc
            #undef rc
            #undef fa
            #undef S
    }LCT;
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        RI i; F.read(n); cnt_real=isrl[1]=id[1]=L[1]=1; R[1]=n;
        for (LCT.link(cnt_all=lst=2,1),F.read(m),i=1;i<=m;++i)
        {
            F.read(opt); F.read(l); F.read(r);
            switch (opt)
            {
                case 0:
                    isrl[id[++cnt_real]=++cnt_all]=1; LCT.link(cnt_all,lst);
                    L[cnt_real]=l; R[cnt_real]=r; break;
                case 1:
                    F.read(x); l=L[x]>l?L[x]:l; r=R[x]<r?R[x]:r;
                    if (l>r) continue;
                    LCT.link(++cnt_all,lst); et[++cnt_et]=event(l,i-m,cnt_all,id[x]);
                    et[++cnt_et]=event(r+1,i-m,cnt_all,lst); lst=cnt_all; break;
                case 2:
                    F.read(x); et[++cnt_et]=event(l,++cnt_q,id[r],id[x]); break;
            }
        }
        for (sort(et+1,et+cnt_et+1),i=1;i<=cnt_et;++i)
        {
            if (et[i].t>0) ans[et[i].t]=LCT.query(et[i].x,et[i].y);
            else LCT.cut(et[i].x),LCT.link(et[i].x,et[i].y);
        }
        for (i=1;i<=cnt_q;++i) F.write(ans[i]); return F.Fend(),0;
    }
    
  • 相关阅读:
    fastjson
    抽象类和接口
    Linux发行版,分类,CentOS下载
    《Head First 设计模式》读后总结:基础,原则,模式
    java.lang.NoSuchMethodError
    在word中优雅地插入代码
    Java读取Maven工程下的配置文件,工具类
    移动互联网10年,传奇一直在发生
    Spring整合MybatisPlus学习笔记
    IDEA环境下SSM整合------注解开发
  • 原文地址:https://www.cnblogs.com/cjjsb/p/12242707.html
Copyright © 2011-2022 走看看