BZOJ 3514 GERALD07加强版 (LCT+主席树)

题目大意:给定n个点m条边无向图,每次询问求当图中有编号为[L,R]的边时,整个图的联通块个数,强制在线

神题!(发现好久以前的题解没有写完诶)

 

我们要求图中联通块的个数,似乎不可搞啊。

联通块个数=n-树边条数!

考虑每条边的贡献,我们按编号从小到大暴力枚举每一条边。

考虑用$LCT$维护森林。

设新加入的这条边编号为$e$,连接了$x,y$两个点

如果$x,y$原来不连通,说明加入$e$会让图中多一条树边。边e对$L\in [1,e],R\geq e$的图$[L,R]$产生一点贡献

如果$x,y$原来就联通,说明加入$e$会产生环,并不会影响联通块个数。我们找出$e$所在环里编号最小的边$x$

当$L\leq x$时,删掉边$x$,图$[L,R]$的树边个数不变。

当$L>x$时,删掉边$x$,会让图$[L,R]$少一条树边。那么边$x$会对$L\in[x+1,e],R\geq e$的的图$[L,R]$产生一点贡献

如何处理询问?我们可以用主席树,主席树不同的根作为右端点,线段树维护对左端点的贡献。每次查询,主席树相减,然后单点查询

如何维护贡献?主席树上打差分实现区间修改

如何维护编号最小的边?把边转化成点扔到$LCT$里就行啦

 

  1 #include <queue>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #define N1 401000
  7 #define M1 201000
  8 #define S1 (N1<<1)
  9 #define T1 (N1<<2)
 10 #define ll long long
 11 #define uint unsigned int
 12 #define rint register int 
 13 #define ull unsigned long long
 14 #define dd double
 15 #define il inline 
 16 #define inf 1000000000
 17 using namespace std;
 18  
 19 int gint()
 20 {
 21     int ret=0,fh=1;char c=getchar();
 22     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 23     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 24     return ret*fh;
 25 }
 26 int n,m,T,type;
 27 struct Edge{
 28 int x[M1],y[M1],cte;
 29 void ae(int u,int v)
 30 {cte++;x[cte]=u,y[cte]=v;}
 31 }E;
 32 struct SEG{
 33 int ls[N1*40],rs[N1*40],sum[N1*40],root[N1],tot;
 34 void pushup(int rt){sum[rt]=sum[ls[rt]]+sum[rs[rt]];}
 35 void build(int l,int r,int &rt)
 36 {   
 37     int mid=(l+r)>>1; rt=++tot;
 38     if(l==r) return;
 39     build(l,mid,ls[rt]);
 40     build(mid+1,r,rs[rt]);
 41 }
 42 void update(int x,int l,int r,int r1,int &r2,int w)
 43 {
 44     if((!r2)||(r1==r2)){r2=++tot,sum[r2]=sum[r1],ls[r2]=ls[r1],rs[r2]=rs[r1];}
 45     if(l==r) {sum[r2]+=w; return;} int mid=(l+r)>>1;
 46     if(x<=mid) update(x,l,mid,ls[r1],ls[r2],w);
 47     else update(x,mid+1,r,rs[r1],rs[r2],w);
 48     pushup(r2);
 49 }
 50 int query(int L,int R,int l,int r,int rt)
 51 {
 52     if(!rt||L>R) return 0;
 53     if(L<=l&&r<=R) return sum[rt];
 54     int mid=(l+r)>>1,ans=0;
 55     if(L<=mid) ans+=query(L,R,l,mid,ls[rt]);
 56     if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]);
 57     return ans; 
 58 }
 59 }s;
 60 namespace lct{
 61 int ch[N1][2],fa[N1],mi[N1],id[N1],rev[N1],tot;
 62 int idf(int x){return ch[fa[x]][0]==x?0:1;}
 63 int isroot(int x){return (ch[fa[x]][0]==x||ch[fa[x]][1]==x)?0:1;}
 64 void pushup(int x){mi[x]=min(x,min(mi[ch[x][0]],mi[ch[x][1]]));}
 65 void revers(int x){swap(ch[x][0],ch[x][1]),rev[x]^=1;}
 66 void pushdown(int x){if(rev[x]){revers(ch[x][0]),revers(ch[x][1]),rev[x]^=1;}}
 67 void rot(int x)
 68 {
 69     int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
 70     if(!isroot(y)) ch[ff][py]=x; fa[x]=ff;
 71     fa[ch[x][px^1]]=y,ch[y][px]=ch[x][px^1];
 72     ch[x][px^1]=y,fa[y]=x;
 73     pushup(y),pushup(x);
 74 }
 75 int stk[N1],tp;
 76 void splay(int x)
 77 {
 78     int y=x; stk[++tp]=x;
 79     while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];}
 80     while(tp){pushdown(stk[tp--]);}
 81     while(!isroot(x))
 82     {
 83         y=fa[x];
 84         if(isroot(y)) rot(x);
 85         else if(idf(y)==idf(x)) rot(y),rot(x);
 86         else rot(x),rot(x);
 87     }
 88 }
 89 void access(int x){for(int y=0;x;y=x,x=fa[x]) splay(x),ch[x][1]=y,pushup(x);}
 90 void mkroot(int x){access(x),splay(x),revers(x);}
 91 void split(int x,int y){mkroot(x),access(y),splay(y);}
 92 int fdroot(int x){access(x),splay(x);while(ch[x][0])pushdown(ch[x][0]),x=ch[x][0];return x;}
 93 void cut(int x,int y){split(x,y);fa[x]=ch[y][0]=0,pushup(y);}
 94 void link(int x,int y){split(x,y);fa[x]=y;}
 95 //int isconn(int x,int y){split(x,y);if(!ch[x][1]&&fa[x]=y&&ch[y][0]==x) return 1;}
 96 void solve(int x,int y,int e)
 97 {
 98     split(x+m,y+m);
 99     if(x==y){
100         int r1=s.root[e-1],r2=s.root[e]=++s.tot;
101         s.sum[r2]=s.sum[r1],s.ls[r2]=s.ls[r1],s.rs[r2]=s.rs[r1];
102     }else if(fdroot(y+m)!=x+m){
103         s.update(1,1,m,s.root[e-1],s.root[e],1);
104         if(e<m) s.update(e+1,1,m,s.root[e-1],s.root[e],-1);
105     }else{
106         int id=mi[y+m],xx=E.x[id],yy=E.y[id];
107         cut(id,xx+m); cut(id,yy+m); 
108         s.update(id+1,1,m,s.root[e-1],s.root[e],1);
109         if(e<m) s.update(e+1,1,m,s.root[e-1],s.root[e],-1);
110     }
111     link(e,x+m),link(e,y+m);
112 }
113 };
114 int tot;
115  
116 int main()
117 {
118     int i,j,x,y,Q,sx,sy,ans=0; tot=n+m;
119     scanf("%d%d%d%d",&n,&m,&Q,&type);
120     for(j=1;j<=m;j++) x=gint(), y=gint(), E.ae(x,y);
121     s.build(1,m,s.root[0]);
122     for(lct::mi[0]=inf,i=1;i<=n+m;i++) lct::mi[i]=i;
123     for(j=1;j<=m;j++)
124     {
125         x=E.x[j]; y=E.y[j];
126         lct::solve(x,y,j);
127     }
128     for(j=1;j<=Q;j++)
129     {
130         x=gint(), y=gint(); 
131         if(type) x^=ans,y^=ans;
132         sx=s.query(1,x,1,m,s.root[x-1]);
133         sy=s.query(1,x,1,m,s.root[y]);
134         ans=n-(sy-sx);
135         printf("%d\n",ans);
136     }
137     return 0;
138 }
139 

 

posted @ 2019-03-21 19:24  guapisolo  阅读(216)  评论(0编辑  收藏  举报