luoguP5385 [Cnoi2019]须臾幻境

题意

首先联通块个数等于总点数-生成森林的边数,于是我们考虑维护原图的一棵生成树。

将边依次加入,用lct维护时间的最大生成树,并记录每条边在哪条边加入时删去,没被删则为(0),设为(f_i)

考虑一次询问,我们查询下([l,r])(f_ileqslant r)的数的个数,这样我们就能知道这个区间被删了多少条边。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+10;
const int inf=1e9;
int n,m,Q,type,lastans;
struct Edge{int u,v;}E[maxn];
inline int read()
{
    char c=getchar();int res=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
int fa[maxn],val[maxn],minn[maxn],f[maxn];
int ch[maxn][2];
bool rev[maxn];
inline bool checkroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline int get(int x){return ch[fa[x]][1]==x;}
inline void up(int x){minn[x]=min(val[x],min(minn[ch[x][0]],minn[ch[x][1]]));}
inline void rotate(int x)
{
	int y=fa[x],z=fa[y],k=get(x),w=ch[x][k^1];
	if(!checkroot(y))ch[z][get(y)]=x;ch[x][k^1]=y,ch[y][k]=w;
	if(w)fa[w]=y;fa[y]=x;fa[x]=z;
	up(y),up(x);
}
inline void reverse(int x){swap(ch[x][0],ch[x][1]);rev[x]^=1;}
inline void down(int x)
{
	if(!rev[x])return;
	if(ch[x][0])reverse(ch[x][0]);
	if(ch[x][1])reverse(ch[x][1]);
	rev[x]=0;
}
inline void splay(int x)
{
	int now=x;
	stack<int>sta;
	sta.push(now);
	while(!checkroot(now))sta.push(fa[now]),now=fa[now];
	while(!sta.empty())down(sta.top()),sta.pop();
	while(!checkroot(x))
	{
		int y=fa[x];
		if(!checkroot(y))rotate(get(x)==get(y)?y:x);
		rotate(x);
	}
}
inline void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,up(x);}
inline void makeroot(int x){access(x);splay(x);reverse(x);}
inline int findroot(int x)
{
	access(x);splay(x);
	while(ch[x][0])down(x),x=ch[x][0];
	splay(x);
	return x;
}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
inline void link(int x,int y){makeroot(x);fa[x]=y;}
inline void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;up(y);}
inline int query(int x,int y){split(x,y);return minn[y];}
int tot;
int root[maxn];
struct Segment_tree
{
	#define lc(p) (seg[p].lc)
	#define rc(p) (seg[p].rc)
	#define sum(p) (seg[p].sum)
	int lc,rc,sum;
}seg[maxn<<5];
void insert(int pre,int &p,int l,int r,int pos)
{
	seg[p=++tot]=seg[pre];sum(p)++;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(pos<=mid)insert(lc(pre),lc(p),l,mid,pos);
	else insert(rc(pre),rc(p),mid+1,r,pos);
}
int query(int p,int l,int r,int ql,int qr)
{
	if(l>=ql&&r<=qr)return sum(p);
	int mid=(l+r)>>1,res=0;
	if(ql<=mid)res+=query(lc(p),l,mid,ql,qr);
	if(qr>mid)res+=query(rc(p),mid+1,r,ql,qr);
	return res;
}
int main()
{
	n=read(),m=read(),Q=read(),type=read();
	for(int i=0;i<=n;i++)val[i]=minn[i]=inf;
	for(int i=1;i<=m;i++)val[i+n]=minn[i+n]=i;
	for(int i=1;i<=m;i++)
	{
		E[i].u=read(),E[i].v=read();
		if(E[i].u==E[i].v){f[i]=i;continue;}
		if(findroot(E[i].u)==findroot(E[i].v))
		{
			int pos=query(E[i].u,E[i].v);
			f[pos]=i;
			cut(E[pos].u,pos+n),cut(E[pos].v,pos+n);
		}
		link(E[i].u,i+n),link(E[i].v,i+n);
	}	
	for(int i=1;i<=m;i++)
	{
		root[i]=root[i-1];
		if(f[i])insert(root[i-1],root[i],0,m,f[i]);
	}
	while(Q--)
	{
		int l=read(),r=read();
		if(type)l=(l+lastans)%m+1,r=(r+lastans)%m+1;
		if(l>r)swap(l,r);
		int tmp=query(root[r],0,m,0,r)-query(root[l-1],0,m,0,r);
		printf("%d
",lastans=n-(r-l+1-tmp));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/nofind/p/13041469.html