BZOJ3514 : Codechef MARCH14 GERALD07加强版

以边编号为权值

用Link-cut Tree维护最大生成树

对于新加的第i条边(u,v)

a[i]表示当a[i]这条边加入后连通块个数会减少

若u==v则a[i]=m

若u与v不连通则连上,a[i]=0

若u与v连通则a[i]为u,v路径上最小值,将那条边断开,连上这条边

查询[l,r]等价于查询[l,r]里有多少a[i]<l

主席树维护

时间复杂度$O((m+k)\log m)$

 

#include<cstdio>

#define N 400010

#define E 200010

#define M 4000010

int f[N],son[N][2],val[N],min[N],tmp[N];bool rev[N];

inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}

inline void swap(int&a,int&b){int c=a;a=b;b=c;}

inline int Min(int a,int b){return a<b?a:b;}

inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}

inline void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}

inline void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}

inline void up(int x){min[x]=Min(val[x],Min(min[son[x][0]],min[son[x][1]]));}

inline void rotate(int x){

  int y=f[x],w=son[y][1]==x;

  son[y][w]=son[x][w^1];

  if(son[x][w^1])f[son[x][w^1]]=y;

  if(f[y]){

    int z=f[y];

    if(son[z][0]==y)son[z][0]=x;

    if(son[z][1]==y)son[z][1]=x;

  }

  f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);

}

inline void splay(int x){

  int s=1,i=x,y;tmp[1]=i;

  while(!isroot(i))tmp[++s]=i=f[i];

  while(s)pb(tmp[s--]);

  while(!isroot(x)){

    y=f[x];

    if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}

    rotate(x);

  }

  up(x);

}

inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}

inline int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}

inline void makeroot(int x){access(x);splay(x);rev1(x);}

inline void link(int x,int y){makeroot(x);f[x]=y;access(x);}

inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}

inline void cut(int x,int y){makeroot(x);cutf(y);}

inline int ask(int x,int y){makeroot(x);access(y);splay(y);return min[y];}

int n,m,i,k,type,x,y,u[E],v[E],a[E],tot,l[M],r[M],sum[M],head[E],last;

int ins(int x,int a,int b,int c){

  int y=++tot;

  sum[y]=sum[x]+1;

  if(a==b)return y;

  int mid=(a+b)>>1;

  if(c<=mid)l[y]=ins(l[x],a,mid,c),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c);

  return y;

}

int query(int x,int a,int b,int c){

  if(!x)return 0;

  if(b<=c)return sum[x];

  int mid=(a+b)>>1,t=query(l[x],a,mid,c);

  if(c>mid)t+=query(r[x],mid+1,b,c);

  return t;

}

int main(){

  read(n);read(m);read(k);read(type);

  for(i=0;i<=n;i++)val[i]=min[i]=1000000000;

  for(i=1;i<=m;i++)val[i+n]=min[i+n]=i;

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

    read(u[i]);read(v[i]);

    if(u[i]==v[i])a[i]=m;

    else if(root(u[i])==root(v[i]))a[i]=ask(u[i],v[i]),cut(u[a[i]],a[i]+n),cut(v[a[i]],a[i]+n),link(u[i],i+n),link(v[i],i+n);

    else link(u[i],i+n),link(v[i],i+n);

  }

  for(i=1;i<=m;i++)head[i]=ins(head[i-1],0,m,a[i]);

  while(k--){

    read(x),read(y);

    if(type)x^=last,y^=last;

    printf("%d\n",last=n-query(head[y],0,m,x-1)+query(head[x-1],0,m,x-1));

  }

  return 0;

}

  

 

你可能感兴趣的:(code)