CF639F Bear and Chemistry

题目传送门

分析:
题目描述的条件实际上是在要求所有点在同一个边双连通分量中
先在原图跑tarjan,缩点建树,
询问的点和加入的边的点处理之后变成边双上的点
然后建虚树,在虚树上跑tarjan就好了
不难,写起来真恶心

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>

#define maxn 600005
#define MOD 1000000007
#define INF 0x3f3f3f3f

using namespace std;

inline long long getint()
{
    long long num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

int n,m,q,R;
int fir[maxn],nxt[maxn],to[maxn],cnt;
int sz[maxn],tp[maxn],fa[maxn],son[maxn],dpt[maxn],pos[maxn],cur;
map<pair<int,int>,int>M;
int p[maxn],V[maxn];
int P_stk[maxn],P_Tp;

inline int rotate(int x){x=(x+R)%n;return x?x:x+n;}
inline bool cmp(int x,int y)
{return pos[x]<pos[y];}
inline void newnode(int u,int v)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void dfs1(int u)
{
	sz[u]=1;pos[u]=++cur;
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa[u])
	{
		fa[to[i]]=u,dpt[to[i]]=dpt[u]+1;
		dfs1(to[i]),sz[u]+=sz[to[i]];
		if(sz[to[i]]>sz[son[u]])son[u]=to[i];
	}
}
inline void dfs2(int u,int ac)
{
	tp[u]=ac;if(son[u])dfs2(son[u],ac);
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa[u]&&to[i]!=son[u])dfs2(to[i],to[i]);
}
inline int LCA(int u,int v)
{
	for(;tp[u]!=tp[v]&&u&&v;u=fa[tp[u]])if(dpt[tp[u]]<dpt[tp[v]])swap(u,v);
	if(!u||!v)return 0;
	return dpt[u]<dpt[v]?u:v;
}

struct node{
	vector<int>G[maxn],Id[maxn];
	int dfn[maxn],low[maxn],tim,vis[maxn],sccno[maxn],scccnt;
	int stk[maxn],Tp;
	
	inline void tarjan(int u)
	{
		dfn[u]=low[u]=++tim;stk[++Tp]=u;
		for(int i=0,v;i<G[u].size();i++)if(!vis[Id[u][i]])
		{
			vis[Id[u][i]]=1;
			if(!dfn[v=G[u][i]])tarjan(v),low[u]=min(low[u],low[v]);
			else if(!sccno[v])low[u]=min(low[u],dfn[v]);
		}
		if(dfn[u]==low[u])
		{
			scccnt++;
			while(1){sccno[stk[Tp]]=scccnt;if(stk[Tp--]==u)break;}
		}
	}
	inline void init()
	{
		for(int i=1;i<=m;i++)
		{
			int u=getint(),v=getint();
			G[u].push_back(v),G[v].push_back(u);
			Id[u].push_back(i),Id[v].push_back(i);
		}
		for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
		for(int u=1;u<=n;u++)for(int i=0;i<G[u].size();i++)if(sccno[G[u][i]]!=sccno[u])
		{
			int x=min(sccno[u],sccno[G[u][i]]),y=max(sccno[u],sccno[G[u][i]]);
			if(!M[make_pair(x,y)])newnode(x,y),newnode(y,x),M[make_pair(x,y)]=1;
		}
	}
}G,H;

int main()
{
	n=getint(),m=getint(),q=getint();
	G.init();
	for(int i=1;i<=G.scccnt;i++)if(!sz[i])dfs1(i),dfs2(i,i);
	for(int t=1;t<=q;t++)
	{
		int N=getint(),M=getint(),K=0,tmp=0;P_Tp=0;
		for(int i=1;i<=N;i++)
		{
			int x=G.sccno[rotate(getint())];
			p[++K]=x,V[x]=1;
		}
		for(int i=1;i<=M;i++)
		{
			int x=G.sccno[rotate(getint())],y=G.sccno[rotate(getint())];
			if(x==y)continue;
			p[++K]=x,p[++K]=y,tmp++;
			H.G[x].push_back(y),H.G[y].push_back(x);
			H.Id[x].push_back(tmp),H.Id[y].push_back(tmp);
		}
		sort(p+1,p+K+1,cmp),K=unique(p+1,p+K+1)-p-1;
		for(int i=K-1;i;i--)
		{
			int x=LCA(p[i],p[i+1]);
			if(x)p[++K]=x;
		}
		sort(p+1,p+K+1,cmp),K=unique(p+1,p+K+1)-p-1;
		for(int i=1;i<=K;i++)
		{
			while(P_Tp&&pos[P_stk[P_Tp]]+sz[P_stk[P_Tp]]<=pos[p[i]])P_Tp--;
			if(P_Tp)
			{
				int x=P_stk[P_Tp],y=p[i];tmp++;
				H.G[x].push_back(y),H.G[y].push_back(x);
				H.Id[x].push_back(tmp),H.Id[y].push_back(tmp);
			}
			P_stk[++P_Tp]=p[i];
		}
		for(int i=1;i<=K;i++)if(!H.dfn[p[i]])H.tarjan(p[i]);
		int pp=0;bool flg=1;
		for(int i=1;i<=K;i++)if(V[p[i]])
		{
			if(!pp)pp=H.sccno[p[i]];
			else if(pp!=H.sccno[p[i]]){flg=0;break;}
		}
		for(int i=1;i<=K;i++)
		{
			H.G[p[i]].clear(),H.Id[p[i]].clear();
			H.dfn[p[i]]=H.low[p[i]]=H.sccno[p[i]]=V[p[i]]=0;
		}
		for(int i=1;i<=tmp;i++)H.vis[i]=0;
		H.scccnt=H.tim=H.Tp=0;
		R=(R+t*flg)%n;
		puts(flg?"YES":"NO");
	}
}

原文地址:https://www.cnblogs.com/Darknesses/p/13052389.html