• bzoj 4573


    LCT神题...

    首先暴力的做法就是每次在一个区间上link,然后暴力查询,时间复杂度$O(爆炸)$

    但是我们可以发现的是,每棵树之间互不影响!

    因此我们可以考虑离线之后分别统计每棵树

    但是这样做其实并没有优化时空啊!

    但是等等,我们在考虑一下:我们的操作都是区间操作,也就是说我们可以用一个类似差分的思想,一棵树一棵树地处理,处理到区间端点的时候修改一些东西就行了!

    那么更换生长节点怎么办?

    我们建立一个虚点表示生长节点,然后把新产生的点都连到这个点上就行

    于是思路就顺理成章了:

    对于新建节点的操作,我们新生成一个点权为1的节点,记录下这个节点生效的区间,然后把他挂到现在的生长节点上

    对于更换生长节点的操作,我们新建一个点权为0的节点,将读入的区间与这个点生效的区间取交集作为有效的区间,在这个区间左端点把他挂在要求的实际节点上,右端点挂回虚节点链上

    对于查询操作,直接用LCA查询即可,求LCA的方法见代码中access函数

    然后离线所有操作,先按树的标号排序(注意新建节点的操作都认为是第一棵树上的,这样后面才能产生足够的节点去移动),先进行修改再进行查询(可以在排序时通过正负把查询排到后面)

    这样问题就解决了

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    using namespace std;
    struct Ques
    {
        int pos,typ;
        int x,y;
        Ques (){}
        Ques (int a,int b,int c,int d):pos(a),typ(b),x(c),y(d){}
        friend bool operator < (Ques a,Ques b)
        {
            return a.pos==b.pos?a.typ<b.typ:a.pos<b.pos;
        }
    }q[400005];
    int ch[400005][2];
    int siz[400005],f[400005],val[400005];
    int ret[400005];
    int fl[400005],fr[400005];
    int lq[400005],rq[400005];
    int n,m,Q;
    int tot=0,cnt=0,ttop=0;
    void update(int x)
    {
        siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+val[x];
    }
    bool be_root(int x)
    {
        if(ch[f[x]][0]==x||ch[f[x]][1]==x)return 0;
        return 1;
    }
    void rotate(int x)
    {
        int y=f[x],z=f[y],k=(ch[y][1]==x);
        if(!be_root(y))ch[z][ch[z][1]==y]=x;
        f[x]=z;
        ch[y][k]=ch[x][!k],f[ch[x][!k]]=y;
        ch[x][!k]=y,f[y]=x;
        update(y),update(x);
    }
    void splay(int x)
    {
        while(!be_root(x))
        {
            int y=f[x],z=f[y];
            if(!be_root(y))
            {
                if((ch[z][1]==y)^(ch[y][1]==x))rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
        //update(x);
    }
    int access(int x)
    {
        int y=0;
        while(x)
        {
            splay(x);
            ch[x][1]=y;
            update(x);
            y=x,x=f[x];
        }
        return y;
    }
    void link(int x,int y)
    {
        splay(x),f[x]=y;
    }
    void cut(int x)
    {
        access(x),splay(x),f[ch[x][0]]=0,ch[x][0]=0,update(x);
    }
    void new_node(int x)
    {
        tot++,val[tot]=siz[tot]=x;
    }
    int query(int x,int y)
    {
        int ret=0,fa;
        access(x),splay(x),ret+=siz[x];
        fa=access(y),splay(y),ret+=siz[y];
        access(fa),splay(fa),ret-=2*siz[fa];
        return ret;
    }
    inline int read()
    {
        int f=1,x=0;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;
    }
    int main()
    {
        n=read(),m=read();
        new_node(1),new_node(0);
        cnt=1,lq[1]=fr[1]=1,rq[1]=n;
        int las=2;link(2,1);
        for(int i=1;i<=m;i++)
        {
            int t=read();
            if(!t)
            {
                int l=read(),r=read();
                new_node(1);
                lq[++cnt]=l,rq[cnt]=r,fr[cnt]=tot;
                q[++ttop]=Ques(1,i-m,tot,las);
            }else if(t==1)
            {
                int l=read(),r=read(),x=read();
                l=max(l,lq[x]),r=min(r,rq[x]);
                if(l<=r)
                {
                    new_node(0),link(tot,las);
                    q[++ttop]=Ques(l,i-m,tot,fr[x]);
                    q[++ttop]=Ques(r+1,i-m,tot,las);
                    las=tot;
                }
            }else
            {
                int x=read(),st=read(),ed=read();
                q[++ttop]=Ques(x,++Q,fr[st],fr[ed]);
            }
        }
        sort(q+1,q+ttop+1);
        int last=1;
        for(int i=1;i<=n;i++)
        {
            while(q[last].pos==i&&last<=ttop)
            {
                if(q[last].typ<=0)cut(q[last].x),link(q[last].x,q[last].y);
                else ret[q[last].typ]=query(q[last].x,q[last].y);
                last++;
            }
        }
        for(int i=1;i<=Q;i++)printf("%d
    ",ret[i]);
        return 0;
    }
  • 相关阅读:
    spark简单入门
    vim 树形目录插件NERDTree
    Windows下查看系统端口使用的命令
    网络爬虫爬取动态网页
    Java并查集链表实现
    基于mahout的海量数据关联规则挖掘
    高维特征降维方法-随机映射
    JVM(4)--垃圾回收算法
    Java高并发程序设计(六)--线程池(1)
    Java高并发程序设计(五)--ReentrantLock源码解析
  • 原文地址:https://www.cnblogs.com/zhangleo/p/11174780.html
Copyright © 2020-2023  润新知