BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ3514


题意概括

  N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

  N,M,Q<=200000


 

题解

  http://hzwer.com/4358.html

  这题hzwer还是写的很好的……


 

代码

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=200005,S=N*2,Inf=23333333;
int n,m,k,type,prev_e[N];
struct Edge{
	int x,y;
}e[N];
int fa[S],son[S][2],rev[S],val[S],Min[S];
void clear(int x,int v){
	fa[x]=son[x][0]=son[x][1]=rev[x]=0;
	val[x]=Min[x]=v;
}
bool isroot(int x){
	return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
void pushup(int x){
	Min[x]=min(val[x],min(Min[son[x][0]],Min[son[x][1]]));
}
void pushdown(int x){
	if (rev[x]){
		rev[x]=0;
		rev[son[x][0]]^=1;
		rev[son[x][1]]^=1;
		swap(son[x][0],son[x][1]);
	}
}
void pushadd(int x){
	if (!isroot(x))
		pushadd(fa[x]);
	pushdown(x);
}
int wson(int x){
	return son[fa[x]][1]==x;
}
void rotate(int x){
	if (isroot(x))
		return;
	int y=fa[x],z=fa[y],L=wson(x),R=L^1;
	if (!isroot(y))
		son[z][wson(y)]=x;
	fa[x]=z,fa[y]=x,fa[son[x][R]]=y;
	son[y][L]=son[x][R],son[x][R]=y;
	pushup(y),pushup(x);
}
void splay(int x){
	pushadd(x);
	for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
		if (!isroot(y))
			rotate(wson(x)==wson(y)?y:x);
}
void access(int x){
	int t=0;
	while (x){
		splay(x);
		son[x][1]=t;
		pushup(x);
		t=x;
		x=fa[x];
	}
}
int find(int x){
	access(x);
	splay(x);
	while (son[x][0])
		x=son[x][0];
	return x;
}
void rever(int x){
	access(x);
	splay(x);
	rev[x]^=1;
}
void link(int x,int y){
	rever(x);
	fa[x]=y;
}
void split(int x,int y){
	rever(x);
	access(y);
	splay(y);
}
void cut(int x,int y){
	split(x,y);
	fa[x]=son[y][0]=0;
}
const int T=5200005;
int ls[T],rs[T],sum[T],root[N],total;
void Tpushup(int rt){
	sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
void build(int &rt,int L,int R){
	rt=++total;
	if (L==R){
		ls[T]=rs[T]=sum[T]=0;
		return;
	}
	int mid=(L+R)>>1;
	build(ls[rt],L,mid);
	build(rs[rt],mid+1,R);
	Tpushup(rt);
}
void add(int prt,int &rt,int L,int R,int pos){
	rt=++total;
	if (L==R){
		sum[rt]=sum[prt]+1;
		return;
	}
	int mid=(L+R)>>1;
	if (pos<=mid)
		add(ls[prt],ls[rt],L,mid,pos),rs[rt]=rs[prt];
	else
		add(rs[prt],rs[rt],mid+1,R,pos),ls[rt]=ls[prt];
	Tpushup(rt);
}
int query(int rt,int L,int R,int pos){
	if (R<=pos)
		return sum[rt];
	if (L>pos)
		return 0;
	int mid=(L+R)>>1;
	return query(ls[rt],L,mid,pos)+query(rs[rt],mid+1,R,pos);
}
int main(){
	scanf("%d%d%d%d",&n,&m,&k,&type);
	for (int i=1;i<=m;i++)
		scanf("%d%d",&e[i].x,&e[i].y);
	int s=n+m;
	for (int i=0;i<S;i++)
		clear(i,Inf);
	for (int i=1;i<=m;i++){
		int x=e[i].x,y=e[i].y;
		if (x==y){
			prev_e[i]=i;
			continue;
		}
		if (find(x)==find(y)){
			split(y,x);
			int ce=prev_e[i]=Min[x];
			cut(e[ce].x,ce+n);
			cut(e[ce].y,ce+n);
		}
		else
			prev_e[i]=0;
		clear(i+n,i);
		link(x,i+n);
		link(y,i+n);
	}
	total=n-1;
	build(root[0],0,m);
	for (int i=1;i<=m;i++)
		add(root[i-1],root[i],0,m,prev_e[i]);
	int lastans=0;
	for (int i=1;i<=k;i++){
		int L,R;
		scanf("%d%d",&L,&R);
		if (type)
			L^=lastans,R^=lastans;
		int res=query(root[R],0,m,L-1)-query(root[L-1],0,m,L-1);
		res=n-res;
		printf("%d\n",lastans=res);
	}
	return 0;
}

  

posted @ 2017-12-15 12:57  zzd233  阅读(302)  评论(0编辑  收藏  举报