[NOI2021] 庆典

\(\text{Problem}:\)[NOI2021] 庆典

\(\text{Solution}:\)

注意题目给出的性质保证了当 \(m=n-1\)​​ 时,给出的图是一棵外向树。由此可以推出,将原图缩点后得到的图,一定由一棵外向树加上若干条从祖先指向后代的边构成。显然,不是外向树上的边没有用,故利用拓扑排序就可以去掉这些无用边。

考虑新加的边会产生哪些路径。不难发现,实际有用的结点(如两路径交点等)极少,故只需对新加边的端点及 \(s,t\) 建一棵虚树。然后从 \(s\) 开始遍历正图,从 \(t\) 开始遍历反图,最后求出交集的答案和即可。

\(\text{Code}:\)

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=300010, M=20;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,Q,K;
int dfn[N],low[N],tim,sta[N],tp,book[N],bl[N],val[N],wal[N],cnt,deg[N],rt;
int f[N],d[N],son[N],siz[N],top[N],id[N],nowid,h[N],dis[N];
int head[N],maxE,ghead[N]; struct Edge { int nxt,to; }e[N<<1],g[N<<1];
struct NEdge { int u,v; }a[N<<1];
inline bool cp(NEdge x,NEdge y) { return x.u==y.u?x.v<y.v:x.u<y.u; }
inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
struct Node { int v,id; };
vector<Node> g1[N],g2[N]; int tot;
int d1[N],d2[N],b1[N],b2[N];
int vc[N];
void Tarjan(int x)
{
	dfn[x]=low[x]=++tim;
	book[x]=1, sta[++tp]=x;
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!dfn[v]) Tarjan(v), low[x]=min(low[x],low[v]);
		else if(book[v]) low[x]=min(low[x],dfn[v]);
	}
	if(dfn[x]==low[x])
	{
		cnt++;
		int y;
		do
		{
			y=sta[tp--];
			book[y]=0, bl[y]=cnt;
			val[cnt]++;
		}while(y!=x);
	}
}
inline void Topo()
{
	queue<int> Q;
	for(ri int i=1;i<=n;i++) if(!deg[i]) Q.push(i);
	while(!Q.empty())
	{
		int x=Q.front(); Q.pop();
		for(ri int i=head[x];i;i=e[i].nxt)
		{
			int v=e[i].to;
			deg[v]--;
			if(!deg[v]) f[v]=x, Q.push(v);
		}
	}
}
void dfs1(int x)
{
	dis[x]=dis[f[x]]+val[x];
	siz[x]=1, d[x]=d[f[x]]+1;
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		dfs1(v);
		siz[x]+=siz[v];
		if(siz[v]>siz[son[x]]) son[x]=v;
	}
}
void dfs2(int x,int topf)
{
	top[x]=topf, id[x]=++nowid;
	if(!son[x]) return;
	dfs2(son[x],topf);
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==f[x]||v==son[x]) continue;
		dfs2(v,v);
	}
}
inline int LCA(int x,int y)
{
	while(top[x]^top[y])
	{
		if(d[top[x]]<d[top[y]]) swap(x,y);
		x=f[top[x]];
	}
	if(d[x]>d[y]) swap(x,y);
	return x;
}
inline bool cp2(int x,int y) { return id[x]<id[y]; }
void DFS1(int x)
{
	d1[x]=1;
	for(auto i:g1[x])
	{
		b1[i.id]=1;
		if(d1[i.v]) continue; 
		DFS1(i.v);
	}
}
void DFS2(int x)
{
	d2[x]=1;
	for(auto i:g2[x])
	{
		b2[i.id]=1;
		if(d2[i.v]) continue;
		DFS2(i.v);
	}
}
signed main()
{
	n=read(), m=read(), Q=read(), K=read();
	for(ri int i=1;i<=m;i++)
	{
		int u,v;
		u=read(), v=read();
		Add(u,v);
		a[i]=(NEdge){u,v};
	}
	for(ri int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i);
	n=cnt, cnt=0;
	for(ri int i=1;i<=m;i++)
	{
		if(bl[a[i].u]!=bl[a[i].v]) a[++cnt].u=bl[a[i].u], a[cnt].v=bl[a[i].v];
	}
	sort(a+1,a+1+cnt,cp), m=0;
	for(ri int i=1;i<=cnt;i++)
	{
		if(i!=1 && a[i].u==a[i-1].u && a[i].v==a[i-1].v) continue;
		a[++m]=a[i];
	}
	memset(head,0,sizeof(head)), maxE=0;
	for(ri int i=1;i<=m;i++)
	{
		Add(a[i].u,a[i].v);
		deg[a[i].v]++;
	}
	Topo();
	memset(head,0,sizeof(head)), maxE=0;
	for(ri int i=1;i<=n;i++)
	{
		if(!f[i]) rt=i;
		else Add(f[i],i);
	}
	d[0]=-1, dfs1(rt), dfs2(rt,rt);
	memset(book,0,sizeof(book));
	for(;Q;Q--)
	{
		int len=0;
		int s,t;
		s=bl[read()], t=bl[read()];
		h[1]=s, h[2]=t;
		len=2;
		for(ri int i=1;i<=K;i++)
		{
			a[i].u=bl[read()], a[i].v=bl[read()];
			h[++len]=a[i].u, h[++len]=a[i].v;
		}
		sort(h+1,h+1+len,cp2); int sz=0;
		for(ri int i=1;i<=len;i++) if(i==1||h[i]!=h[i-1]) h[++sz]=h[i];
		len=sz, sz=0;
		sta[tp=1]=rt; tot=0;
		for(ri int i=1;i<=len;i++)
		{
			if(h[i]==rt) continue;
			int pp=LCA(h[i],sta[tp]);
			if(pp^sta[tp])
			{
				while(id[pp]<id[sta[tp-1]])
				{
					tot++; b1[tot]=b2[tot]=0;
					wal[tot]=dis[sta[tp]]-dis[sta[tp-1]]-val[sta[tp]];
					g1[sta[tp-1]].eb((Node){sta[tp],tot});
					vc[++sz]=sta[tp-1], vc[++sz]=sta[tp];
					tp--;
				}
				if(id[pp]>id[sta[tp-1]])
				{
					g1[pp].clear();
					tot++; b1[tot]=b2[tot]=0;
					wal[tot]=dis[sta[tp]]-dis[pp]-val[sta[tp]];
					g1[pp].eb((Node){sta[tp],tot});
					vc[++sz]=pp, vc[++sz]=sta[tp];
					sta[tp]=pp;
				}
				else
				{
					tot++; b1[tot]=b2[tot]=0;
					wal[tot]=dis[sta[tp]]-dis[pp]-val[sta[tp]];
					g1[pp].eb((Node){sta[tp],tot});
					vc[++sz]=pp, vc[++sz]=sta[tp]; 
					tp--;
				}
			}
			g1[h[i]].clear(), sta[++tp]=h[i];
		}
		for(ri int i=1;i<tp;i++)
		{
			tot++; b1[tot]=b2[tot]=0;
			wal[tot]=dis[sta[i+1]]-dis[sta[i]]-val[sta[i+1]];
			g1[sta[i]].eb((Node){sta[i+1],tot});
			vc[++sz]=sta[i], vc[++sz]=sta[i+1];
		}
		for(ri int i=1;i<=K;i++)
		{
			tot++; b1[tot]=b2[tot]=0;
			wal[tot]=0;
			g1[a[i].u].eb((Node){a[i].v,tot});
			vc[++sz]=a[i].u,vc[++sz]=a[i].v;
		}
		sort(vc+1,vc+sz+1); int nsz=0;
		for(ri int i=1;i<=sz;i++) if(i==1 || vc[i]!=vc[i-1]) vc[++nsz]=vc[i];
		sz=nsz;
		for(ri int i=1;i<=sz;i++)
		{
			for(auto j:g1[vc[i]]) g2[j.v].eb((Node){vc[i],j.id});
		}
		DFS1(s); DFS2(t);
		int ans=0;
		for(ri int i=1;i<=sz;i++) if(d1[vc[i]]&&d2[vc[i]]) ans+=val[vc[i]];
		for(ri int i=1;i<=tot;i++) if(b1[i]&&b2[i]) ans+=wal[i];
		for(ri int i=1;i<=sz;i++)
		{
			g1[vc[i]].clear();
			g2[vc[i]].clear();
			d1[vc[i]]=d2[vc[i]]=0;
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2021-07-30 10:13  zkdxl  阅读(118)  评论(0编辑  收藏  举报