bzoj 3514 Codechef MARCH14 GERALD07加强版

bzoj

题目要的连通块个数可以表示为点数\(-\)所有生成树上的边数.考虑这个生成树边数,我们维护编号最大生成树,按照编号加入边,然后如果加的时候会成环就把环上编号最小的边挤掉,并且当前的第\(i\)条边的前驱边\(pre_i\)为刚才被挤掉的第\(j\)条边,如果没有前驱边就是0

然后对于一个询问,我们只把使得联连通块个数减少的边放在生成树上,也就是如果区间\([l,r]\)中同时存在\(i\)\(pre_i\),就不统计\(i\)的贡献,那么有贡献的边都会满足\(pre_i<l\le i\le r\),这个可以建出主席树后二维数点实现

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=2e5+10,inf=1<<30;
int rd()
{
	int x=0,w=1;char ch=0;
	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
int n,m,q,op,ans,e[N<<1][2];
int fa[N<<1],ch[N<<1][2],id[N<<1];
bool tg[N<<1];
bool nrt(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
void psup(int x){id[x]=min(x<=n?inf:x,min(id[ch[x][0]],id[ch[x][1]]));}
void rev(int x){if(x) tg[x]^=1,swap(ch[x][0],ch[x][1]);}
void psdn(int x){if(tg[x]) rev(ch[x][0]),rev(ch[x][1]),tg[x]=0;}
void ppush(int x)
{
	if(nrt(x)) ppush(fa[x]);
	psdn(x);
}
void rot(int x)
{
	int y=fa[x],z=fa[y],ty=ch[y][1]==x,w=ch[x][!ty];
	if(nrt(y)) ch[z][ch[z][1]==y]=x;
	ch[x][!ty]=y,ch[y][ty]=w;
	if(w) fa[w]=y;
	fa[y]=x,fa[x]=z;
	psup(y);
}
void spl(int x)
{
	ppush(x);
	while(nrt(x))
	{
		int y=fa[x],z=fa[y];
		if(nrt(y)) ((ch[y][1]==x)^(ch[z][1]==y))?rot(x):rot(y);
		rot(x);
	}
	psup(x);
}
void acs(int x)
{
	for(int y=0;x;y=x,x=fa[x])
		spl(x),ch[x][1]=y,psup(x);
}
void mkrt(int x){acs(x),spl(x),rev(x);}
void split(int x,int y){mkrt(x),acs(y),spl(y);}
int fdrt(int x)
{
	acs(x),spl(x);
	psdn(x);
	while(ch[x][0]) x=ch[x][0],psdn(x);
	return x;
}
void link(int i)
{
	int x=e[i][0],y=e[i][1];
	mkrt(x),mkrt(y);
	fa[x]=fa[y]=i;
}
void cut(int i)
{
	int x=e[i][0],y=e[i][1];
	split(x,y);
	spl(i);
	ch[i][0]=ch[i][1]=fa[x]=fa[y]=0;
}
vector<int> pt[N];
vector<int>::iterator it;
int s[N*30],sn[N*30][2],rt[N],tt;
void inst(int o1,int o2,int x)
{
	s[o1]=s[o2]+1;
	int l=1,r=m;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(x<=mid)
		{
			sn[o1][0]=++tt,sn[o1][1]=sn[o2][1];
			o1=sn[o1][0],o2=sn[o2][0];
			r=mid;
		}
		else
		{
			sn[o1][0]=sn[o2][0],sn[o1][1]=++tt;
			o1=sn[o1][1],o2=sn[o2][1];
			l=mid+1;
		}
		s[o1]=s[o2]+1;
	}
}
int quer(int o,int l,int r,int ll,int rr)
{
	if(!s[o]||ll>rr) return 0;
	if(ll<=l&&r<=rr) return s[o];
	int an=0,mid=(l+r)>>1;
	if(ll<=mid) an+=quer(sn[o][0],l,mid,ll,rr);
	if(rr>mid) an+=quer(sn[o][1],mid+1,r,ll,rr);
	return an;
}

int main()
{
	n=rd(),m=rd(),q=rd(),op=rd();
	id[0]=inf;
	for(int i=1;i<=m;++i)
	{
		e[i+n][0]=rd(),e[i+n][1]=rd();
		if(e[i+n][0]==e[i+n][1]) continue;
		if(fdrt(e[i+n][0])==fdrt(e[i+n][1]))
		{
			split(e[i+n][0],e[i+n][1]);
			int ii=id[e[i+n][1]];
			pt[ii-n].push_back(i);
			cut(ii);
		}
		else pt[0].push_back(i);
		link(i+n);
	}
	for(int i=1;i<=m;++i)
	{
		rt[i]=rt[i-1];
		for(it=pt[i-1].begin();it!=pt[i-1].end();++it)
		{
			int x=*it,las=rt[i];
			inst(rt[i]=++tt,las,x);
		}
	}
	while(q--)
	{
		int l=rd()^(ans*op),r=rd()^(ans*op);
		ans=n-quer(rt[l],1,m,l,r);
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2019-10-13 19:56  ✡smy✡  阅读(178)  评论(0编辑  收藏  举报