CF1137C 题解

考虑把每个点进行拆成 \(d\) 个点表示星期几走到这个点,那么原图上的边 \((u,v)\) 就被拆成\((pos_{u,i},pos_{v,i+1})\) 表示星期的变化。

然后考虑进行缩点,在一个强连通分量内的同一个博物馆只能被计算一次?

那要是一个博物馆出现在两个强连通分量内呢?

可以证明这种情况不会出现,因为边 \((pos_{u,i},pos_{v,j})\) 和边 \((pos_{v,j},pos_{u,k})\) 代表原图中存在边 \((u,v)\)\((v,u)\) 且类似的可以证明一个博物馆拆成的点一定在一个强连通分量中,那么接下来计算强连通分量内的贡献,拓扑排序后跑一遍最长路即可。

// LUOGU_RID: 122368344
#include<bits/stdc++.h>
#define pos(i,j)((i-1)*d+j-1)
using namespace std;
int n,d,m;
const int maxn = 1e5*51+1;
struct Node{
	int v,to;
}e1[maxn<<1],e2[maxn<<1];
int tot1,tot2;
int head[maxn][2];
void add1(int u,int v){
	e1[++tot1].v=v;
	e1[tot1].to=head[u][0];
	head[u][0]=tot1;
}
void add2(int u,int v){
	e2[++tot2].v=v;
	e2[tot2].to=head[u][1];
	head[u][1]=tot2;
}
int dfncnt,vis[maxn],dfn[maxn],low[maxn],color,col[maxn];
bitset<maxn> point;
stack<int> st;
void tanjan(int u){
	st.push(u);
	vis[u]=1;
	low[u]=dfn[u]=++dfncnt;
	for(int i=head[u][0];i;i=e1[i].to){
		int v=e1[i].v;
		if(dfn[v]==0){
			tanjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]==1){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(dfn[u]==low[u]){
		++color;
		while(st.top()!=u){
			col[st.top()]=color;	
			vis[st.top()]=0;
			st.pop();
		}
		col[u]=color;
		vis[u]=0;
		st.pop();
	}
}
void bfs(){//处理从 1 号节点出发可以抵达的点 
	for(int i=1;i<=color;i++) low[i]=0; 
	queue<int> q;
	q.push(col[pos(1,1)]);
	while(q.size()>0){
		int u=q.front();
		q.pop();
		for(int i=head[u][1];i;i=e2[i].to){
			int v=e2[i].v;
			low[v]++;
			if(low[v]==1) q.push(v);
		}
	}
}
unordered_map<int,int> use[100001];
void build(){//处理缩点后的连边 
	for(int u=pos(1,1);u<=pos(n,d);u++){
		for(int i=head[u][0];i;i=e1[i].to){
			int v=e1[i].v;
			int U=col[u],V=col[v];
			if(U==V) continue;
			add2(U,V);
		}
	}
	for(int i=1;i<=color;i++) vis[i]=0;
	for(int u=pos(1,1);u<=pos(n,d);u++){
		if(point[u]==1&&use[u/d][col[u]]==0){
			vis[col[u]]++;
			use[u/d][col[u]]=1;
		}
	}
}
int answer;
void topo(){
	queue<int> q;
	for(int i=1;i<=color;i++) dfn[i]=-1000000;
	dfn[col[pos(1,1)]]=vis[col[pos(1,1)]];
	q.push(col[pos(1,1)]);
	while(q.size()>0){
		int u=q.front();
		q.pop();
		for(int i=head[u][1];i;i=e2[i].to){
			int v=e2[i].v;
			dfn[v]=max(dfn[v],dfn[u]+vis[v]);
			low[v]--;
			if(low[v]==0) q.push(v);
		}
	}
	for(int i=1;i<=color;i++) answer=max(answer,dfn[i]);
}  
int main(){
	cin>>n>>m>>d;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		for(int j=1;j<=d;j++) add1(pos(u,j),pos(v,j%d+1));
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=d;j++){
			char c;
			cin>>c;
			point[pos(i,j)]=c-'0';
		}
	}
	for(int i=pos(1,1);i<=pos(n,d);i++) if(dfn[i]==0) tanjan(i);
	build();
	bfs();
	topo();
	cout<<answer<<'\n';
}
posted @ 2024-01-31 00:00  ChiFAN鸭  阅读(5)  评论(0编辑  收藏  举报