BZOJ 3514 Codechef MARCH14 GERALD07加强版

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3514

题意:给出一个图m条边。每次询问只加入编号在区间[L,R]之内的边有多少连通块。在线。

思路:求出[1,i]边加入时的最大生成树,即加入在[1,i]中不在生成树上的边时连通块不变。假如是离线,那么我们按照询问右端点排序,每次维护区间[L,R]中在生成树上的边即可。

现在是在线,我们用可持久化线段树维护。直观想,每次加入一条边时连通块数减少1。但是加入边R时存在环的时候这个就不满足了。设这个环上编号最小的边的编号为x,那么x一旦加入,即L<=x<R时,那么加入R时连通块数就不会再减少。因此我们在函数式线段树中的[L,R]查找区间[0,L-1]的和即可。

 

struct node

{

    int Min,val,isReversed;

    node *c[2],*f;

   

    inline void reverse()

    {

        isReversed^=1;

        swap(c[0],c[1]);

    }

};

   

node a[N<<1],*nullNode;

   

inline void pushUp(node *p)

{

    if(p==nullNode) return;

    p->Min=p->val;

    if(p->c[0]!=nullNode) p->Min=min(p->Min,p->c[0]->Min);

    if(p->c[1]!=nullNode) p->Min=min(p->Min,p->c[1]->Min);

}

   

   

   

inline void pushDown(node *p)

{

    if(p->isReversed)

    {

        if(p->c[0]!=nullNode) p->c[0]->reverse();

        if(p->c[1]!=nullNode) p->c[1]->reverse();

        p->isReversed=0;

    }

}

   

inline void rotate(node *p,int k)

{

    node *q=p->f;

    q->c[k]=p->c[!k];

    if(p->c[!k]!=nullNode) p->c[!k]->f=q;

    p->c[!k]=q;

    p->f=q->f;

    if(q->f!=nullNode)

    {

        if(p->f->c[0]==q) p->f->c[0]=p;

        if(p->f->c[1]==q) p->f->c[1]=p;

    }

    q->f=p;

    pushUp(q);

}

   

inline int isRoot(node *p)

{

    return p->f==nullNode||p->f->c[0]!=p&&p->f->c[1]!=p;

}

   

   

void splay(node *p)

 {

     pushDown(p);

     while (!isRoot(p))

     {

         if(isRoot(p->f))

         {

             pushDown(p->f);

             pushDown(p);

             if(p==p->f->c[0]) rotate(p,0);

             else rotate(p,1);

         }

         else

         {

             pushDown(p->f->f);

             pushDown(p->f);

             pushDown(p);

             if(p->f->f->c[0]==p->f)

             {

                 if(p->f->c[0]==p) rotate(p->f,0);

                 else rotate(p,1);

                 rotate(p,0);

             }

             else

             {

                 if(p->f->c[1]==p) rotate(p->f,1);

                 else rotate(p,0);

                 rotate(p,1);

             }

         }

     }

     pushUp(p);

}

   

node* access(node *p)

{

    node *q=nullNode;

    while(p!=nullNode)

    {

        splay(p);

        p->c[1]=q;

        pushUp(p);

        q=p;

        p=p->f;

    }

    return q;

}

   

   

    

  

int connected(int x,int y)

{

    access(a+y);

    node *p=a+x;

    while(p!=nullNode)

    {

        splay(p);

        if(p->f==nullNode) break;

        p=p->f;

    }

    while(p->c[1]!=nullNode) p=p->c[1];

    return p==a+y;

}

  

void join(int x,int y)

{

    access(a+x);

    splay(a+x);

    a[x].reverse();

    a[x].f=a+y;

}

   

void cut(int x,int y)

{

    access(a+x);splay(a+y);

    if(a[y].f==a+x) a[y].f=nullNode;

    else

    {

        access(a+y);

        splay(a+x);

        a[x].f=nullNode;

    }

}

    

int query(int x,int y)

{

    access(a+x);

    node *p=a+y;

    node *q=nullNode;

    for(;p!=nullNode;p=p->f)

    {

        splay(p);

        if(p->f==nullNode)

        {

            int ans=p->val;

            if(q!=nullNode) ans=min(ans,q->Min);

            if(p->c[1]!=nullNode) ans=min(ans,p->c[1]->Min);

            return ans;

        }

        p->c[1]=q;

        q=p;

        pushUp(q);

    }

}

   

int n,m,Q;

   

  

struct segNode

{

    int L,R,sum;

};

  

  

segNode A[N*20];

int e;

  

int root[N<<1];

  

int add(int t,int L,int R,int p)

{

    int x=++e;

    if(L==R)

    {

        A[x].sum=A[t].sum+1;

        return x;

    }

    A[x].L=A[t].L;

    A[x].R=A[t].R;

    int M=(L+R)>>1;

    if(p<=M) A[x].L=add(A[t].L,L,M,p);

    else A[x].R=add(A[t].R,M+1,R,p);

    A[x].sum=A[A[x].L].sum+A[A[x].R].sum;

    return x;

}

  

  

int type;

  

int edge[N][2];

 

void init()

{

    nullNode=new node();

    nullNode->isReversed=0;

    nullNode->Min=INF;

    nullNode->val=INF;

    nullNode->c[0]=nullNode->c[1]=nullNode->f=nullNode;

  

    n=getInt();

    m=getInt();

    Q=getInt();

    type=getInt();

    int i;

    for(i=1;i<=n+m;i++)

    {

        if(i<=n) a[i].val=a[i].Min=INF;

        else a[i].val=a[i].Min=i-n;

        a[i].c[0]=a[i].c[1]=a[i].f=nullNode;

    }

    for(i=1;i<=m;i++) scanf("%d%d",&edge[i][0],&edge[i][1]);

    for(i=1;i<=m;i++)

    {

        int u=edge[i][0];

        int v=edge[i][1];

        if(u==v)

        {

            root[i]=root[i-1];

            continue;

        }

        if(connected(u,v))

        {

            int t=query(u,v);

            cut(n+t,edge[t][0]);

            cut(n+t,edge[t][1]);

            root[i]=add(root[i-1],0,m,t);

            join(i+n,u);

            join(i+n,v);

        }

        else

        {

            root[i]=add(root[i-1],0,m,0);

            join(i+n,u);

            join(i+n,v);

        }

    }

}

  

int query(int x,int y,int L,int R,int ll,int rr)

{

    if(L==ll&&R==rr) return A[x].sum-A[y].sum;

    int M=(L+R)>>1;

    if(rr<=M) return query(A[x].L,A[y].L,L,M,ll,rr);

    if(ll>M) return query(A[x].R,A[y].R,M+1,R,ll,rr);

      

    int ans=query(A[x].L,A[y].L,L,M,ll,M);

    ans+=query(A[x].R,A[y].R,M+1,R,M+1,rr);

    return ans;

}

   

int main()

{

  

    init();

    int ans=0;

    while(Q--)

    {

        int L=getInt();

        int R=getInt();

        if(type) L^=ans,R^=ans;

        ans=n-query(root[R],root[L-1],0,m,0,L-1);

        printf("%d\n",ans);

    }

}

 

你可能感兴趣的:(code)