BZOJ3514: Codechef MARCH14 GERALD07加强版

主席树+LCT
每次加边的时候判断一下是否成环
如果没有就加进去否则弹出环内比序号最小边
然后统计答案

#include
#include
#include
#include
#include
using namespace std;

char c;
inline void read(int &a)
{
    a=0;do c=getchar();while(c<'0'||c>'9');
    while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}

struct Node
{
    int data;
    Node *lc,*rc,*f,*min;
    int  Rev;
    inline bool H(){return f->lc==this||f->rc==this;}
    inline bool l(){return f->lc==this;}
}*empty;
inline void Begin()
{
    empty=new Node;
    empty->lc=empty->rc=empty->min=empty;
    empty->data=1<<29;
}
inline Node*New_Node()
{
    Node *tp=new Node;
    tp->lc=tp->rc=empty;
    tp->min=0;
    tp->Rev=0;
    tp->f=tp;
    return tp;  
}
Node Poi[200001];
struct S
{
    int x,y;
}L[200001];

inline void updata(Node *a)
{a->min=(a->lc->min->datarc->min->data)?a->lc->min:a->rc->min;a->min=(a->min->data>a->data)?a:a->min;}
inline void LC(Node *a)
{
    Node *ne;
    if(a->f->H())
       if(a->f->l())
          a->f->f->lc=a,ne=a->f->f;
       else
          a->f->f->rc=a,ne=a->f->f;
    else if(a->f->f!=a->f)
          ne=a->f->f;
        else
           ne=a; 
   a->rc->f=a->f;
   a->f->lc=a->rc;
   a->rc=a->f;
   a->f->f=a;
   a->f=ne;
   updata(a->rc),updata(a);
}

inline void RC(Node *a)
{
    Node *ne;
    if(a->f->H())
       if(a->f->l())
          a->f->f->lc=a,ne=a->f->f;
       else
          a->f->f->rc=a,ne=a->f->f;
    else if(a->f->f!=a->f)
          ne=a->f->f;
        else
           ne=a; 
   a->lc->f=a->f;
   a->f->rc=a->lc;
   a->lc=a->f;
   a->f->f=a;
   a->f=ne;
   updata(a->lc),updata(a);
}
inline void pushdown(Node *a){Node *lc=a->lc;a->lc=a->rc,a->rc=lc;a->lc->Rev^=1,a->rc->Rev^=1,a->Rev^=1;}
inline void Turn(Node *a)
{a->l()?LC(a):RC(a);}
inline void Twi(Node *a)
{
    if(a->f->f->Rev)pushdown(a->f->f);
    if(a->f->Rev)pushdown(a->f);
    if(a->Rev)pushdown(a);
    a->f->l()==a->l()?Turn(a->f):Turn(a);Turn(a);
}
inline void Onc(Node *a)
{
    if(a->f->Rev)pushdown(a->f);
    if(a->Rev)pushdown(a);
    Turn(a);
}
inline void Splay(Node *a)
{
    while(a->H()&&a->f->H())Twi(a);
    while(a->H())Onc(a);
}

inline void Access(Node *a)
{
    Splay(a);
    while(true)
     {
        Splay(a);
        if(a->f==a)
          return;
        Splay(a->f);
        if(a->f->Rev)pushdown(a->f);
        a->f->rc=a;
     }
}
inline void MakeRoot(Node *a)
{
    Access(a);
    a->lc->Rev^=1;
    a->lc=empty;
}

inline int Cut(Node *a,Node *b)
{
    MakeRoot(a);
    Access(b);
    Node *tp;
    while(a->f!=b)
       Onc(a);
    tp=a->rc->min;

    Node *t1=&Poi[L[tp->data].x],*t2=&Poi[L[tp->data].y];
    MakeRoot(t1);Access(t2);
    while(t1->f!=t2)
       Onc(t1);
    t2->lc=empty;
    t1->f=t1;
    return tp->data;
}

inline void Link(Node *a,Node *b,int data)
{
MakeRoot(a);
Access(b);
Node *c=New_Node();
a->f=c;
c->rc=a;
c->data=data;
c->f=b;
updata(c);
}

struct Seg
{
    Seg *lc,*rc;
    int l,r;
    int data;
};
Seg *History[200001];
Seg*Build(int l,int r)
{
    Seg *tp=new Seg;
    tp->l=l,tp->r=r,tp->data=0;
    tp->lc=NULL;tp->rc=NULL;
    if(l^r)
       tp->lc=Build(l,(l+r)>>1),
       tp->rc=Build(((l+r)>>1)+1,r);
    return tp;

}

Seg *Modify(Seg *old,int place)
{
    Seg*tp=new Seg;
    *tp=*old;
    if(old->l^old->r)
      {
          if(place<=old->lc->r)
             tp->lc=Modify(tp->lc,place);
            else
             tp->rc=Modify(tp->rc,place);
         tp->data=tp->lc->data+tp->rc->data;
      } 
    else
       tp->data++;
    return tp;
}

int Query(Seg *pl,int l)
{
     if(!pl)return 0;
     if(ll)return 0;
     if(pl->r<=l)return pl->data;
     return Query(pl->lc,l)+Query(pl->rc,l);
}
int F[200001];
int find(int x){return F[x]=(F[x]==x?x:find(F[x]));}
int Union(int x,int y){F[find(x)]=find(y);}

int main()
{
    int n,m,k,type,i,j;
    read(n);
    Begin();
    Node *t=New_Node();
    for(i=1;i<=n;i++)
      F[i]=i,Poi[i]=*t,Poi[i].min=&Poi[i],
      Poi[i].f=&Poi[i],
      Poi[i].data=1<<28;
    read(m);
    read(k);
    read(type);
    int tp;
    History[0]=Build(0,200002);
    for(i=1;i<=m;i++)
       {
          tp=0;
          read(L[i].x),read(L[i].y);
          if(find(L[i].x)^find(L[i].y))
             {
                Union(L[i].x,L[i].y);
                Link(&Poi[L[i].x],&Poi[L[i].y],i);
              }
            else if(L[i].x!=L[i].y)
               {
                tp=Cut(&Poi[L[i].x],&Poi[L[i].y]);
                Link(&Poi[L[i].x],&Poi[L[i].y],i);
               }
            else tp=200002;
         History[i]=Modify(History[i-1],tp);
       }

    int l,r,lastans=0;
    for(i=1;i<=k;i++)
      {
        read(l),read(r);
        if(type) 
         l^=lastans,r^=lastans;
        if(l>r)swap(l,r);
        int Pop=Query(History[r],l-1)-Query(History[l-1],l-1);

        printf("%d\n",lastans=(n-Pop));
      }


    return 0;
}

你可能感兴趣的:(数据结构,主席树(可持久化线段树,Link,Cut,Tree,线段树)