BZOJ 3514: Codechef MARCH14 GERALD07加强版 【LCT+主席树求图的连通块个数】

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/88732136

题目描述:

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

题目分析:

图的连通块个数肿么求?

按编号顺序依次加边。
如果边 i i 加入的时候形成了环,那么把环中最先加入的边 j j 找到,令 p r e [ i ] = j pre[i]=j ,并把 j j 断掉。
如果没有成环,那么 p r e [ i ] = 0 pre[i]=0

区间 [ l , r ] [l,r] 的边中连通两个连通块的边就是那些 p r e [ i ] &lt; l pre[i]&lt;l 的边。
如果pre[i]>=l,说明这个连通块中最先加入的边都>=l,那么i一定没有造成贡献
如果pre[i]<l,那么l到i-1的边一定不能构成原来完整的连通块,i一定会造成贡献
(这个过程类似于做"区间中出现过的数的贡献")

加边断边的过程用LCT维护,求在 [ l , r ] [l,r] 内且 p r e [ i ] &lt; l pre[i]&lt;l i i 的个数用主席树查询。

然而我的maxn刚好开200000,极限数据爆炸,硬是调了3h+,把整段代码全部改掉就是没有改maxn,自闭。。。

Code:

#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
const int maxn = 200005;
const int maxp = maxn*20;
using namespace std;
inline void read(int &a){
    char c;bool f=0;
	while(!isdigit(c=getchar())) if(c=='-') f=1;
    for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
	if(f) a=-a;
}
namespace LCT{
	const int N = 400005;
	int ch[N][2],fa[N],v[N],pos[N],tot,nb[N][2];
	bool rev[N];
	#define il inline
	#define lc ch[x][0]
	#define rc ch[x][1]
	il bool isr(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
	il bool isc(int x){return ch[fa[x]][1]==x;}
	il void upd(int x){
		pos[x]=x;
		if(v[pos[x]]>v[pos[lc]]) pos[x]=pos[lc];
		if(v[pos[x]]>v[pos[rc]]) pos[x]=pos[rc];
	}
	il void pushdown(int x){
		if(rev[x]){
			swap(lc,rc),rev[x]=0;
			if(lc) rev[lc]^=1; if(rc) rev[rc]^=1;
		}
	}
	il void pdpath(int x){if(!isr(x)) pdpath(fa[x]);pushdown(x);}
	il void rot(int x){
		int y=fa[x],z=fa[y],c=isc(x);
		if(!isr(y)) ch[z][isc(y)]=x;
		(ch[y][c]=ch[x][!c])&&(fa[ch[x][!c]]=y);
		fa[ch[x][!c]=y]=x,fa[x]=z;
		upd(y),upd(x);
	}
	il void splay(int x){
		pdpath(x);
		for(;!isr(x);rot(x))
			if(!isr(fa[x])) rot(isc(fa[x])==isc(x)?fa[x]:x); 
	}
	il int access(int x,int y=0){
		for(;x;x=fa[y=x]) splay(x),ch[x][1]=y,upd(x);
		return y;
	}
	il void bert(int x){access(x),splay(x),rev[x]^=1;}
	il int sert(int x){access(x),splay(x);for(;lc;x=lc);return x;}
	il void link(int x,int y){bert(x),fa[x]=y;}
	il void cut(int x,int y){bert(x),access(y),splay(y);fa[x]=ch[y][0]=0,upd(y);}
	il int split(int x,int y){bert(x),access(y),splay(y); return y;}
	il bool judge(int x,int y){bert(x);return sert(y)==x;}
	il int insert(int x,int y,int w){
		int tmp=0;
		if(judge(x,y)){
			int p=pos[split(x,y)]; tmp=v[p];
			cut(nb[p][0],p),cut(p,nb[p][1]);
		}
		v[++tot]=w,pos[tot]=tot,nb[tot][0]=x,nb[tot][1]=y;
		link(x,tot),link(tot,y);
		return tmp;
	}
	#undef lc 
	#undef rc
}
int n,m,Q,tp,ans;
int rt[maxn],lc[maxp],rc[maxp],s[maxp],tot;
void insert(int &now,int l,int r,int pos){
	s[++tot]=s[now]+1,lc[tot]=lc[now],rc[tot]=rc[now];
	now=tot;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(pos<=mid) insert(lc[now],l,mid,pos);
	else insert(rc[now],mid+1,r,pos);
}
int query(int now,int p,int l,int r,int x){
	if(x==r||!now) return s[now]-s[p];
	int mid=(l+r)>>1;
	if(x<=mid) return query(lc[now],lc[p],l,mid,x);
	else return s[lc[now]]-s[lc[p]]+query(rc[now],rc[p],mid+1,r,x);
}
int main()
{
	int x,y;
	read(n),read(m),read(Q),read(tp),LCT::tot=n;
	for(int i=0;i<=n;i++) LCT::v[i]=m+1;
	for(int i=1;i<=m;i++){
		read(x),read(y);
		if(x==y) {rt[i]=rt[i-1];continue;}
		insert(rt[i]=rt[i-1],0,m-1,LCT::insert(x,y,i));
	}
	while(Q--){
		read(x),read(y);if(tp) x^=ans,y^=ans;
		printf("%d\n",ans=n-query(rt[y],rt[x-1],0,m-1,x-1));
	}
}

猜你喜欢

转载自blog.csdn.net/C20181220_xiang_m_y/article/details/88732136