1. 程式人生 > >【BZOJ3514】Codechef MARCH14 GERALD07加強版 LCT+主席樹

【BZOJ3514】Codechef MARCH14 GERALD07加強版 LCT+主席樹

hup zoj ostream ces 刪除 logs [1] data class

【BZOJ3514】Codechef MARCH14 GERALD07加強版

Description

N個點M條邊的無向圖,詢問保留圖中編號在[l,r]的邊的時候圖中的聯通塊個數。

Input

第一行四個整數N、M、K、type,代表點數、邊數、詢問數以及詢問是否加密。
接下來M行,代表圖中的每條邊。
接下來K行,每行兩個整數L、R代表一組詢問。對於type=0的測試點,讀入的L和R即為詢問的L、R;對於type=1的測試點,每組詢問的L、R應為L xor lastans和R xor lastans。

Output

K行每行一個整數代表該組詢問的聯通塊個數。

Sample Input

3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2

Sample Output

2
1
3
1

HINT

對於100%的數據,1≤N、M、K≤200,000。

題解:本題思路很神~

我們將邊按編號一條一條地加到圖中,如果當前邊a,b所在的連通塊已經連通,則我們找到這個連通塊中編號最小的邊,記錄它的編號kick[i],並將它刪去,然後將當前邊加入到圖中。這個可以用LCT很容易的實現。(套路:用LCT維護邊權的方法,將邊變成點,a-b連邊視為a-c-b連邊,然後圖中只有從邊變過來的點才有權值)

然後采用主席樹,在i的主席樹中將kick[i]刪除,然後查詢[l,r]時再r的主席樹中查詢[l,r]這段區間,就能得到區間中有多少樹邊了。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=200010;
int n,m,Q,typ,tot,ans;
int pa[maxn],pb[maxn],f[maxn],rt[maxn],sum[maxn];
struct LCT
{
	int ch[2],fa,rev,mn,val;
}t[maxn<<1];
struct sag
{
	int ls,rs,siz;
}s[maxn*40];
inline bool isr(int x) {return t[t[x].fa].ch[0]!=x&&t[t[x].fa].ch[1]!=x;}
inline void rever(int x)
{
	swap(t[x].ch[0],t[x].ch[1]),t[x].rev^=1;
}
inline void pushdown(int x)
{
	if(t[x].rev)
	{
		if(t[x].ch[0])	rever(t[x].ch[0]);
		if(t[x].ch[1])	rever(t[x].ch[1]);
		t[x].rev=0;
	}
}
inline void pushup(int x)
{
	t[x].mn=min(t[x].val,min(t[t[x].ch[0]].mn,t[t[x].ch[1]].mn));
}
inline void rotate(int x)
{
	int y=t[x].fa,z=t[y].fa,d=(x==t[y].ch[1]);
	if(!isr(y))	t[z].ch[y==t[z].ch[1]]=x;
	t[x].fa=z,t[y].fa=x,t[y].ch[d]=t[x].ch[d^1];
	if(t[x].ch[d^1])	t[t[x].ch[d^1]].fa=y;
	t[x].ch[d^1]=y;
	pushup(y),pushup(x);
}
void updata(int x)
{
	if(!isr(x))	updata(t[x].fa);
	pushdown(x);
}
inline void splay(int x)
{
	updata(x);
	while(!isr(x))
	{
		int y=t[x].fa,z=t[y].fa;
		if(!isr(y))
		{
			if((x==t[y].ch[1])^(y==t[z].ch[1]))	rotate(x);
			else	rotate(y);
		}
		rotate(x);
	}
}
inline void access(int x)
{
	for(int y=0;x;splay(x),t[x].ch[1]=y,pushup(x),y=x,x=t[x].fa);
}
inline void maker(int x)
{
	access(x),splay(x),rever(x);
}
inline void link(int a,int b)
{
	maker(a),t[a].fa=b;
}
inline void cut(int a,int b)
{
	maker(a),access(b),splay(b),t[a].fa=t[b].ch[0]=0,pushup(b);
}
void insert(int x,int &y,int l,int r,int a,int b)
{
	y=++tot,s[y].siz=s[x].siz+1;
	if(l==r)	return ;
	int mid=(l+r)>>1;
	if(a<=mid)	s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a,b);
	else	s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a,b);
}
int query(int x,int l,int r,int a,int b)
{
	if(!x||(a<=l&&r<=b))	return s[x].siz;
	int mid=(l+r)>>1;
	if(b<=mid)	return query(s[x].ls,l,mid,a,b);
	if(a>mid)	return query(s[x].rs,mid+1,r,a,b);
	return query(s[x].ls,l,mid,a,b)+query(s[x].rs,mid+1,r,a,b);
}
int find(int x)
{
	return (f[x]==x)?x:(f[x]=find(f[x]));
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd(),Q=rd(),typ=rd();
	int i,a,b,c;
	for(i=0;i<=n;i++)	f[i]=i,t[i].val=t[i].mn=m+1;
	for(i=1;i<=m;i++)	t[i+n].val=t[i+n].mn=i;
	for(i=1;i<=m;i++)
	{
		a=pa[i]=rd(),b=pb[i]=rd(),sum[i]=sum[i-1]+1;
		if(a==b)	sum[i]--,rt[i]=rt[i-1];
		else	if(find(a)==find(b))
		{
			maker(a),access(b),splay(b),c=t[b].mn;
			insert(rt[i-1],rt[i],1,m,c,1);
			cut(pa[c],c+n),cut(pb[c],c+n),link(a,i+n),link(b,i+n);
		}
		else	f[f[a]]=f[b],link(a,i+n),link(b,i+n),rt[i]=rt[i-1];
	}
	for(i=1;i<=Q;i++)
	{
		a=rd()^(ans*typ),b=rd()^(ans*typ);
		ans=n-(sum[b]-sum[a-1]-query(rt[b],1,m,a,b));
		printf("%d\n",ans);
	}
	return 0;
}//3 5 4 0 1 3 1 2 2 1 3 2 2 2 2 3 1 5 5 5 1 2 

【BZOJ3514】Codechef MARCH14 GERALD07加強版 LCT+主席樹