专栏文章

【0】做题心得 - 2025 NOIP #67 - T2 / 题解:P13118 [GCJ 2019 #2] Contransmutation【Tarjan】【图论】【缩点】【动态规划】

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min1t0p8
此快照首次捕获于
2025/12/01 19:10
3 个月前
此快照最后确认于
2025/12/01 19:10
3 个月前
查看原文
如此成绩,何以 PION。你首先考虑一个无限的情况是怎么样的。你会发现在强连通分量里面有完全なるの黄金回旋エネルギー,可以无限传递。当这个 SCC 内的边数与点数相等时就显然有每个点最大为他们的和。要是边数更多一点,就显然有无限传递。缩点后这就显然是一个 DAG,直接做即可。注意判断 00,也就是没有病毒的情况。
CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+10;
const ll P=1e9+7;
ll d[N]; bool z[N];
int n,a[N],cnt[N],deg[N];
int id[N],low[N],ic;
int sid[N],stk[N],top,sd,sz[N];
vector<int>e[N],g[N],nd[N];
bool vis[N];
void tarjan(int p){
	stk[++top]=p;
	id[p]=low[p]=++ic;
	for(auto v:e[p]){
		if(!id[v]){
			tarjan(v);
			low[p]=min(low[p],low[v]);
		}else if(!sid[v])
			low[p]=min(low[p],id[v]);
	}
	if(low[p]==id[p]){
		++sd;
		int q=stk[top];
		do{
			q=stk[top], --top;
			sid[q]=sd;
			sz[sd]++;
			d[sd]=(d[sd]+a[q])%P;
			z[sd]=z[sd]|bool(a[q]);
			nd[sd].push_back(q);
		}while(p!=q);
	}
	return;
}
queue<int>q;
int main(){
	freopen("virus.in","r",stdin);
	freopen("virus.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		int u,v;
		cin>>u>>v;
		e[i].push_back(u);
		e[i].push_back(v);
	}
	for(int i=1;i<=n;i++)
		cin>>a[i];
	for(int i=1;i<=n;i++)if(!id[i])
		tarjan(i);
	for(int i=1;i<=n;i++)for(auto v:e[i])
		if(sid[i]==sid[v]) cnt[sid[i]]++;
		else g[sid[i]].push_back(sid[v]), deg[sid[v]]++;
	for(int i=1;i<=sd;i++)
		if(!deg[i]) q.push(i);
	while(q.size()){
		int p=q.front();
		q.pop();
		if(cnt[p]>sz[p]&&z[p]) d[p]=-1;
		for(auto v:g[p]){
			z[v]=z[v]|z[p];
			if(d[p]==-1||d[v]==-1||(cnt[p]==sz[p]&&z[p])) d[v]=-1;
			else d[v]=(d[v]+d[p])%P;
			if(!(--deg[v])) q.push(v);
		}
	}
	for(int i=1;i<=n;i++)
		cout<<d[sid[i]]<<" ";
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...