[bzoj3514]Codechef MARCH14 GERALD07加强版

来自FallDream的博客,未经允许,请勿转载,谢谢。


N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。 n,m<=200000 强制在线

如果我能知道每条边在什么时候有贡献,我就能算出答案,所以考虑找到最迟的和它冲突的边。

找的方法可以以编号为边权,用一个LCT维护最大生成树,每次如果冲突就找到最小的边替换,而它起作用的时间段就是这条边之后。

算答案明显可以主席树,所以这道题就解决啦。

 

#include<iostream>
#include<cstdio>
#define MN 200000
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;
}

int n,m,k,type,last,fa[MN+5],c[MN+5][2],f[MN+5],p[MN+5],q[MN+5],top,mx[MN+5],L[MN+5],R[MN+5],rt[MN+5],cnt=0;
struct node{int l,r,x;}T[MN*25];
bool rev[MN+5];
struct edge{int from,to;}e[MN+5];

inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
inline void update(int x)
{
    int l=c[x][0],r=c[x][1];
    L[x]=f[x];R[x]=p[x];
    mx[x]=max(p[x],f[x]);
    if(l)  L[x]=L[l],mx[x]=max(mx[x],mx[l]);
    if(r)  R[x]=R[r],mx[x]=max(mx[x],mx[r]);
}
void pushdown(int x)
{
    if(x&&rev[x])
    {
        int l=c[x][0],r=c[x][1];
        rev[l]^=1;rev[r]^=1;rev[x]^=1;
        swap(f[l],p[l]);swap(L[l],R[l]);
        swap(f[r],p[r]);swap(L[r],R[r]);
        swap(c[x][0],c[x][1]);
    }
}

void rotate(int x)
{
    int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
    if(!isroot(y)) c[z][c[z][1]==y]=x;
    fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
    c[y][l]=c[x][r];c[x][r]=y;
    update(y);update(x);
}

void splay(int x)
{
    q[top=1]=x;
    for(int t=fa[x];t;t=fa[t]) q[++top]=t;
    for(;top;--top) pushdown(q[top]);
    for(;!isroot(x);rotate(x))
        if(!isroot(fa[x])) rotate((c[fa[fa[x]]][1]==fa[x]^c[fa[x]][1]==x)?x:fa[x]);
}

void access(int x)
{
    for(int y=0;x;x=fa[y=x])
        splay(x),c[x][1]=y,p[x]=L[y],update(x); 
}


void link(int x,int y,int z)
{
    access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]); 
    access(y);c[y][1]=x;fa[x]=y;f[x]=p[y]=z;
    update(x);update(y);
}

void cut(int x,int y)
{
    access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]);
    access(y);splay(y);c[y][0]=fa[x]=f[y]=p[x]=0;
    update(x);update(y);
}

void ins(int x,int nx,int k)
{
    int l=0,r=m,mid;
    while(l<r)
    {
        mid=l+r>>1;
        if(k<=mid)
        {
            T[nx].r=T[x].r;T[nx].l=++cnt;
            x=T[x].l;nx=T[nx].l;r=mid;
        }
        else
        {
            T[nx].l=T[x].l;T[nx].r=++cnt;
            x=T[x].r;nx=T[nx].r;l=mid+1;
        }
        T[nx].x=T[x].x+1;
    }
}

int query(int x,int nx,int k)
{
    int sum=0,l=0,r=m,mid;
    while(l<r)
    {
        mid=l+r>>1;
        if(k>mid) sum+=T[T[nx].l].x-T[T[x].l].x,x=T[x].r,nx=T[nx].r,l=mid+1;
        else x=T[x].l,nx=T[nx].l,r=mid;
    }
    return sum+T[nx].x-T[x].x;
}

int main()
{
    n=read();m=read();k=read();type=read();
    for(int i=1;i<=m;i++) e[i].from=read(),e[i].to=read();
    for(int i=1;i<=m;i++)
    {
        int res=0,x=e[i].from,y=e[i].to;
        if(x!=y)
        {
            access(x);splay(x);rev[x]^=1;swap(f[x],p[x]);swap(L[x],R[x]);
            access(y);splay(y);
            if(!isroot(x)) res=mx[y],cut(e[m+1-res].from,e[m+1-res].to);
            link(x,y,m+1-i);ins(rt[i-1],rt[i]=++cnt,res?m+1-res:0);
        } 
        else rt[i]=rt[i-1];
    }    
    for(int i=1;i<=k;i++)
    {
        int l=read()^(last*type),r=read()^(last*type);
        printf("%d\n",last=n-query(rt[l-1],rt[r],l-1));
    }
    return 0;
}

 

posted @ 2017-04-13 16:39  FallDream  阅读(168)  评论(0编辑  收藏  举报