• [BZOJ]3514: Codechef MARCH14 GERALD07加强版


    Time Limit: 60 Sec  Memory Limit: 256 MB

    Description

      N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

    Input

      第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
      接下来M行,代表图中的每条边。
      接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

    Output

      K行每行一个整数代表该组询问的联通块个数。

    Sample Input

      3 5 4 0
      1 3
      1 2
      2 1
      3 2
      2 2
      2 3
      1 5
      5 5
      1 2

    Sample Output

      2
      1
      3
      1

    HINT

      对于100%的数据,1≤N、M、K≤200,000。

      2016.2.26提高时限至60s

    Solution

      对每条边预处理出最右的询问左端点满足从这个左端点开始向右把边加入图中,加到这条边时该边的两个点已经在一个联通块内,可以这么做:从左到右把所有边加入图中,实时用LCT维护图的最大生成树(森林),其中边权为边的编号,每次若两个点未联通我们直接连(并且我们知道这条边没有满足条件的左端点),否则找到两点在树上的链中边权最小的边把它删掉,这条边的编号就是我们要求的左端点,然后再把新加的边连上,顺带一提,LCT维护边可以对每个点维护其到树上父亲和偏爱子节点的边的编号。预处理出这些之后回答询问就很容易了,我们把区间内的边数扣掉区间内求出的左端点在询问区间内的边(用主席树可以维护),用点数减掉这些边数即可。总复杂度O(nlogn),常数较大。

    Code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    char B[1<<26],*S=B,C;int X;
    inline int read()
    {
        while((C=*S++)<'0'||C>'9');
        for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=X*10+C-'0';
        return X;
    }
    #define MN 200000
    #define ND 4000000
    #define L(x) c[x][0]
    #define R(x) c[x][1]
    int fa[MN+5],c[MN+5][2],tf[MN+5],tc[MN+5],mn[MN+5],rv[MN+5],z[MN+5],zn;
    struct node{int l,r,s;}t[ND+5];
    int x[MN+5],y[MN+5],rt[MN+5],tn;
    inline bool isc(int x){return L(fa[x])==x||R(fa[x])==x;}
    inline int MiN(int a,int b){return a?b?min(a,b):a:b;}
    inline void up(int x){mn[x]=MiN(MiN(tf[x],tc[x]),MiN(mn[L(x)],mn[R(x)]));}
    inline void rev(int x){swap(L(x),R(x));swap(tf[x],tc[x]);rv[x]^=1;}
    inline void down(int x){if(rv[x])rev(L(x)),rev(R(x)),rv[x]=0;}
    void rotate(int x)
    {
        int f=fa[x],ff=fa[f],l=R(f)==x,r=l^1;
        if(isc(f))c[ff][R(ff)==f]=x;
        fa[f]=x;fa[x]=ff;fa[c[x][r]]=f;
        c[f][l]=c[x][r];up(c[x][r]=f);
    }
    void splay(int x)
    {
        for(int i=z[zn=1]=x;isc(i);)i=z[++zn]=fa[i];
        while(zn)down(z[zn--]);
        for(int f;isc(x);rotate(x))
            if(isc(f=fa[x]))rotate(L(fa[f])==f^L(f)==x?x:f);
        up(x);
    }
    void access(int x)
    {
        for(int i=0,it=0;x;x=fa[i=x])
        {
            splay(x);tc[x]=tf[it];R(x)=i;up(x);
            for(it=x;L(it);)down(it),it=L(it);
        }
    }
    bool same(int x,int y)
    {
        access(x);splay(x);rev(x);
        access(y);splay(y);
        return isc(x);
    }
    void link(int x,int y,int i)
    {
        access(x);splay(x);rev(x);
        access(y);splay(y);
        fa[R(y)=x]=y;tf[x]=tc[y]=i;
        up(x);up(y);
    }
    void cut(int x,int y)
    {
        access(x);splay(x);rev(x);
        access(y);splay(y);
        L(y)=fa[x]=tc[x]=tf[y]=0;
        up(x);up(y);
    }
    int add(int k,int l,int r,int x)
    {
        int p=++tn,mid=l+r>>1;
        t[p].s=t[k].s+1;
        if(l<r)if(x<=mid)t[p].l=add(t[k].l,l,mid,x),t[p].r=t[k].r;
                    else t[p].l=t[k].l,t[p].r=add(t[k].r,mid+1,r,x);
        return p;
    }
    int query(int kl,int kr,int l,int r,int ql,int qr)
    {
        if(l==ql&&r==qr)return t[kr].s-t[kl].s;
        int mid=l+r>>1;
        if(qr<=mid)return query(t[kl].l,t[kr].l,l,mid,ql,qr);
        if(ql>mid)return query(t[kl].r,t[kr].r,mid+1,r,ql,qr);
        return query(t[kl].l,t[kr].l,l,mid,ql,mid)+query(t[kl].r,t[kr].r,mid+1,r,mid+1,qr);
    }
    int main()
    {
        fread(B,1,1<<26,stdin);
        int m,n,k,t,i,j,l;
        m=read();n=read();k=read();t=read();
        for(i=1;i<=n;++i)
        {
            x[i]=read();y[i]=read();rt[i]=rt[i-1];
            if(x[i]==y[i]){rt[i]=add(rt[i],1,n,i);continue;}
            if(same(x[i],y[i]))rt[i]=add(rt[i],1,n,l=mn[y[i]]),cut(x[l],y[l]);
            link(x[i],y[i],i);
        }
        for(l=0;k--;t?0:l=0)i=read()^l,j=read()^l,
            printf("%d
    ",l=m-j+i-1+query(rt[i-1],rt[j],1,n,i,j));
    }
  • 相关阅读:
    CSS浮动(float、clear)通俗讲解
    JAVA 类的加载
    数据库操作 delete和truncate的区别
    正则表达式 匹配相同数字
    Oracle EBS OM 取消订单
    Oracle EBS OM 取消订单行
    Oracle EBS OM 已存在的OM订单增加物料
    Oracle EBS OM 创建订单
    Oracle EBS INV 创建物料搬运单头
    Oracle EBS INV 创建物料搬运单
  • 原文地址:https://www.cnblogs.com/ditoly/p/BZOJ3514.html
Copyright © 2020-2023  润新知