CF639F Bear and Chemistry

一、题目

点此看题

二、解法

多练练这种大数据结构其实也挺好😕,那些比较难写的东西多写写就熟练了,话说这道题又是我自己想出来的

题目就是要你判断这些点是否在一个强连通块内,可以转化成判断两点是否在强连通块内。

我们考虑原图的一个生成树,那么添加一条非树边就相当于把树上的一个环缩成一个点。但实际上不需要缩点,我们可以把这条路径上的边全部染色,那么如果两点的树上路径全是被染色的边就说明在一个强连通块内。

因为题目要求强制在线所以我们可以考虑一些在线的数据结构,比如 \(\tt lct\),考虑如果一条边连接了不同连通块内的点就直接合并,否则我们把路径 \(\tt split\) 出来置 \(0\),因为需要支持赋值标记的撤销,所以一开始需要保证所有边权都是 \(1\)也就是需要先缩点,建出缩点之后的生成树

这道题的加密方式很离谱,题目中的 \(R\) 就是如果答案为 Yes 增加询问组数的大小。注意因为我们要把边变成点连上去,所以注意数据不要开小了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cassert>
#include <stack>
using namespace std;
const int M = 300005;
const int N = 1200005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,q,t,tot,ans,vi[M],ea[M],eb[M],ec[M];
int Ind,cnt,dfn[M],low[M],col[M],f[M],st[M],siz[N];
int sum[N],fl[N],cov[N],ch[N][2],fa[N],a[N],b[N];
struct edge{int v,next;}e[N];stack<int> s;
void dfs(int u,int fa)
{
	low[u]=dfn[u]=++Ind;s.push(u);
	for(int i=f[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(!dfn[v])
		{
			dfs(v,i);
			low[u]=min(low[u],low[v]);
		}
		else if(i^fa^1)
			low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		int v;++cnt;
		do
		{
			v=s.top();s.pop();
			col[v]=cnt;
		}while(v^u);
	}
}
//namespace : link-cut-tree
void up(int x)
{
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+a[x];
	sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+a[x]*b[x];
}
int chk(int x)
{
	return ch[fa[x]][1]==x;
}
int nrt(int x)
{
	return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
void flip(int x)
{
	if(!x) return ;
	swap(ch[x][0],ch[x][1]),fl[x]^=1;
}
void cover(int x,int y)
{
	if(!x) return ;
	cov[x]=b[x]=y;sum[x]=siz[x]*y;
}
void down(int x)
{
	if(fl[x]) flip(ch[x][0]),flip(ch[x][1]),fl[x]=0;
	if(cov[x]!=-1) cover(ch[x][0],cov[x])
	,cover(ch[x][1],cov[x]),cov[x]=-1;
}
void rotate(int x)
{
	int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1];
	ch[y][k]=w;fa[w]=y;
	if(nrt(y)) ch[z][chk(y)]=x;fa[x]=z;
	ch[x][k^1]=y;fa[y]=x;
	up(y);up(x);
}
void splay(int x)
{
	int y=x,z=0;st[++z]=y;
	while(nrt(y)) st[++z]=y=fa[y];
	while(z) down(st[z--]);
	while(nrt(x))
	{
		y=fa[x];
		if(nrt(y))
		{
			if(chk(x)==chk(y)) rotate(y);
			else rotate(x);
		}
		rotate(x);
	}
}
void access(int x)
{
	for(int y=0;x;x=fa[y=x])
		splay(x),ch[x][1]=y,up(x);
}
void makert(int x)
{
	access(x);splay(x);flip(x);
}
int findrt(int x)
{
	access(x);splay(x);
	while(ch[x][0]) down(x),x=ch[x][0];
	splay(x);return x;
}
void split(int x,int y)
{
	makert(x);access(y);splay(y);
}
void link(int x,int y)
{
	assert(findrt(x)!=findrt(y));
	makert(x);makert(y);
	fa[x]=y;
}
void cut(int x,int y)
{
	split(x,y);
	fa[x]=ch[y][0]=0;up(y);
}
int ask(int x,int y)
{
	split(x,y);return sum[y];
}
void add(int x,int y,int c)
{
	split(x,y);cover(y,c);
}
int get()
{
	int x=(read()+ans)%n;
	return x==0?n:x;
}
signed main()
{
	n=read();m=read();q=read();tot=1;
	memset(cov,-1,sizeof cov);
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();
		e[++tot]=edge{v,f[u]},f[u]=tot;
		e[++tot]=edge{u,f[v]},f[v]=tot;
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) dfs(i,0);
	t=cnt;
	for(int u=1;u<=n;u++)
		for(int i=f[u];i;i=e[i].next)
		{
			int v=e[i].v,x=col[u],y=col[v];
			if(findrt(x)!=findrt(y))
			{
				t++;a[t]=b[t]=1;up(t);
				link(x,t);link(y,t);
			}
		}
	for(int Case=1;Case<=q;Case++)
	{
		int ni=read(),mi=read(),f=1;
		for(int i=1;i<=ni;i++) vi[i]=col[get()];
		for(int i=1;i<=mi;i++)
		{
			int u=col[get()],v=col[get()];
			ea[i]=u;eb[i]=v;ec[i]=0;
			if(findrt(u)!=findrt(v))
			{
				ec[i]=++t;a[t]=b[t]=1;up(t);
				link(u,t);link(v,t);
			}
			else add(u,v,0);
		}
		for(int i=1;i<ni;i++)
			if(findrt(vi[i])!=findrt(vi[i+1])
			|| ask(vi[i],vi[i+1])>0)
			{
				f=0;
				break;
			}
		if(f) puts("YES"),ans=(ans+Case)%n;
		else puts("NO");
		for(int i=mi;i>=1;i--)
		{
			int u=ea[i],v=eb[i];
			if(ec[i]) cut(u,ec[i]),cut(v,ec[i]);
			else add(u,v,1);
		}
	}
}
posted @ 2021-11-14 21:43  C202044zxy  阅读(182)  评论(0编辑  收藏  举报