zoukankan      html  css  js  c++  java
  • bzoj3514 Codechef MARCH14 GERALD07加强版

    题目描述

    题解:

    貌似是LCT的套路题?

    就是建主席树,然后每次形成环时将环中的第一条边送给新边作标记。

    维护这种恶心东西当然用LCT了。

    这道题还不同于裸一点的LCT题。本题要对于每条边新建一个节点(类似圆方树),然后将时间信息放到新建节点上。

    最后每次查询只需要查标记小于l的边就行了。

    因为标记小于l说明踢掉了一条不属于当前集合的边,最后剩下的只有有用的边了。

    每条有用的边会干掉一个联通块。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 200050
    inline int rd()
    {
        int f=1,c=0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
        return f*c;
    }
    int n,m,K,typ,ans;
    struct EG
    {
        int f,t;
    }e[N];
    struct segtree
    {
        int rt[N],tot,ls[40*N],rs[40*N],v[40*N];
        void update(int u)
        {
            v[u] = v[ls[u]] + v[rs[u]];
        }
        void insert(int l,int r,int &u,int k,int qx)
        {
            u = ++tot;
            ls[u] = ls[k],rs[u] = rs[k],v[u] = v[k]+1;
            if(l==r)return ;
            int mid = (l+r)>>1;
            if(qx<=mid)insert(l,mid,ls[u],ls[k],qx);
            else insert(mid+1,r,rs[u],rs[k],qx);
        }
        int query(int l,int r,int ul,int ur,int ql,int qr)
        {
            if(l==ql&&r==qr)return v[ur]-v[ul];
            int mid = (l+r)>>1;
            if(qr<=mid)return query(l,mid,ls[ul],ls[ur],ql,qr);
            else if(ql>mid)return query(mid+1,r,rs[ul],rs[ur],ql,qr);
            else return query(l,mid,ls[ul],ls[ur],ql,mid)+query(mid+1,r,rs[ul],rs[ur],mid+1,qr);
        }
    }tr1;
    struct LCT
    {
        int fa[N*2],ch[N*2][2],v[N*2],mn[N*2];
        bool res[N*2];
        bool isroot(int x)
        {
            return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
        }
        void update(int x)
        {
            mn[x] = x;
            if(v[mn[ch[x][0]]]<v[mn[x]])mn[x]=mn[ch[x][0]];
            if(v[mn[ch[x][1]]]<v[mn[x]])mn[x]=mn[ch[x][1]];
        }
        void reser(int x)
        {
            res[x]^=1;
            swap(ch[x][0],ch[x][1]);
        }
        void pushdown(int x)
        {
            if(res[x])
            {
                reser(ch[x][0]);
                reser(ch[x][1]);
                res[x]=0;
            }
        }
        int st[N],tl;
        void down(int x)
        {
            st[tl=1]=x;
            while(!isroot(x))x=fa[x],st[++tl]=x;
            while(tl)pushdown(st[tl]),tl--;
        }
        void rotate(int x)
        {
            int y = fa[x],z = fa[y],k = (ch[y][1]==x);
            if(!isroot(y))ch[z][ch[z][1]==y]=x;
            fa[x] = z;
            ch[y][k] = ch[x][!k], fa[ch[x][!k]] = y;
            ch[x][!k] = y,fa[y] = x;
            update(y),update(x);
        }
        void splay(int x)
        {
            down(x);
            while(!isroot(x))
            {
                int y = fa[x],z = fa[y];
                if(!isroot(y))
                    (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
                rotate(x);
            }
        }
        void access(int x)
        {
            int y = 0;
            while(x)
            {
                splay(x);
                ch[x][1]=y;
                update(x);
                y = x,x = fa[x];
            }
        }
        void mtr(int x)
        {
            access(x);
            splay(x);
            reser(x);
        }
        int findrt(int x)
        {
            access(x),splay(x);
            while(ch[x][0])x=ch[x][0];
            return x;
        }
        void link(int x,int y)
        {
            mtr(x);
            fa[x]=y;
        }
        void cut(int x,int y)
        {
            mtr(x);
            access(y);
            splay(y);
            ch[y][0]=fa[x]=0;
            update(y);
        }
        int query(int x,int y)
        {
            mtr(x);
            access(y);
            splay(y);
            return mn[y];
        }
    }tr2;
    int ntr[N];
    void init()
    {
        for(int f,t,i=1;i<=m;i++)
        {
            f = e[i].f,t = e[i].t;
            if(f==t)
            {
                ntr[i] = i;
                continue;
            }
            if(tr2.findrt(f)==tr2.findrt(t))
            {
                int tmp = tr2.query(f,t);
                int edg = tr2.v[tmp];
                tr2.cut(e[edg].f,tmp);
                tr2.cut(e[edg].t,tmp);
                ntr[i] = edg;
            }
            tr2.v[i+n] = i;
            tr2.link(i+n,f);
            tr2.link(i+n,t);
        }
        for(int i=1;i<=m;i++)
            tr1.insert(0,m,tr1.rt[i],tr1.rt[i-1],ntr[i]);
    }
    int main()
    {
        n = rd(),m = rd(),K = rd(),typ = rd();
        for(int f,t,i=1;i<=m;i++)
        {
            f = rd(),t = rd();
            e[i].f=f,e[i].t=t;
        }
        tr2.v[0]=0x3f3f3f3f;
        for(int i=1;i<=n+m;i++)
        {
            tr2.mn[i]=i;
            tr2.v[i]=0x3f3f3f3f;
        }
        init();
        for(int l,r,i=1;i<=K;i++)
        {
            l=rd(),r=rd();
            if(typ)l^=ans,r^=ans;
            if(l>r)swap(l,r);
            ans = n-tr1.query(0,m,tr1.rt[l-1],tr1.rt[r],0,l-1);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    API之绘图(转)
    API之子窗口创建 (转)
    函数调用规范__cdecl和__stdcall的区别一目了然(表格形式)(二)
    _cdecl 和_stdcall及其他调用方式 (一)
    sizeof的深入理解
    VC++中2进制,10进制,16进制相互转换
    传说中的数据结构
    字符串扩展
    数据结构实验之链表七:单链表中重复元素的删除
    数据结构实验之栈一:进制转换
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10165180.html
Copyright © 2011-2022 走看看