专栏文章

Diligent-OI R2 C 题解

P13823题解参与者 7已保存评论 6

文章操作

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

当前评论
6 条
当前快照
1 份
快照标识符
@mipfzkhy
此快照首次捕获于
2025/12/03 11:23
3 个月前
此快照最后确认于
2025/12/03 11:23
3 个月前
查看原文
出题人题解。
首先显然能注意到:将图看成连通图后,同一个连通块里的就能相互转移。于是,每个点的答案肯定是连通块里的最大值之一转移到的。
这个题中,一条边相对于某个点来说是入边还是出边已经不重要了,因为都可以通过这条边进入或走出某个点。于是为了方便并不产生误导,将原来的某个点的入边称为 A 边,原来某个点的出边称为 B 边。
不难发现,从一个点的 A 边进入某个点,再从 B 边出去,这种情况不消耗代价,B 边进入、A 边出去也一样。只有从一个点的 A 边进入、A 边出去,或者 B 边进入、B 边出去,才会消耗 11 步。
于是,对于每个点,我们需要考虑的边有四类:从 A 边或 B 边进来或出去都需要考虑。于是不难想到拆点:
然后,所有原图中的边 uvu\rarr v 可以拆成两条:uu 的 B2 连向 vv 的 A1、从 vv 的 A2 连向 uu 的 B1。
显然这样的拆点方式,仅仅使得点和边的规模都扩大了常数倍。其实可以合并 A1 和 B2,再合并 A2 和 B1,做到一个点仅拆成两个点。但是为了较好理解还是选择了上面的方法。
最后每个连通块独立,在新图中跑 01bfs 即可。因为最大值可能有多个,所以把它们都设为起点。
时间复杂度 O(n+m)O(n+m)
以下是由 jasmine0201编写的代码:
CPP
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5,M=2*N;
int n,m,d[4*N],a[4*N],b[4*N],s[4*N];
struct edge1 {int cnt,head[4*N],nxt[4*M],to[4*M],w[4*M]; } ed;
struct edge2 {int cnt,head[N],nxt[M],to[M]; } Ed;
void addedge(int u,int v,int p){
	ed.to[++ed.cnt] = v;
	ed.nxt[ed.cnt] = ed.head[u];
	ed.head[u] = ed.cnt;
    ed.w[ed.cnt] = p;
}
void addEdge(int u,int v){
	Ed.to[++Ed.cnt] = v;
	Ed.nxt[Ed.cnt] = Ed.head[u];
	Ed.head[u] = Ed.cnt;
}
int dfs(int x){
	if(b[x]) return s[x];
	b[x]=1;
	s[x]=a[x];
	// for(int i=0;i<Ed[x].size();i++) s[x]=max(s[x],dfs(Ed[x][i]));
    for(int i=Ed.head[x];i;i=Ed.nxt[i]) s[x]=max(s[x],dfs(Ed.to[i]));
	return s[x];
}
void dfs1(int x,int num){
	if(s[x]==-1) return;
	s[x]=-1;
	if(a[x]<num) b[x]=0;
	// for(int i=0;i<Ed[x].size();i++) dfs1(Ed[x][i],num);
    for(int i=Ed.head[x];i;i=Ed.nxt[i]) dfs1(Ed.to[i],num);
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
	int n;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++){
		addedge(i*4+1,i*4+3,0);
		addedge(i*4+2,i*4+4,0);
		addedge(i*4+1,i*4+4,1);
		addedge(i*4+2,i*4+3,1);
	}
	int u,v;
	for(int i=1;i<=m;i++){
		cin>>u>>v;
		addedge(u*4+3,v*4+1,0);
		addedge(v*4+4,u*4+2,0);
		addEdge(u,v);
		addEdge(v,u);
	}
	for(int i=1;i<=n;i++) dfs(i);
	for(int i=1;i<=n;i++) dfs1(i,s[i]);
	deque<int> q;
	for(int i=1;i<=n;i++){
		if(b[i]){
			q.push_back(i*4+1); d[i*4+1]=1;
			q.push_back(i*4+2); d[i*4+2]=1;
		}
	}
	while(!q.empty()){
		int x=q.front();q.pop_front();
		for(int i=ed.head[x];i;i=ed.nxt[i]){
			int v=ed.to[i];
			if(d[v]<=d[x]+ed.w[i]&&d[v]!=0) continue;
			d[v]=d[x]+ed.w[i];
			if(ed.w[i]==0) q.push_front(v);
			else q.push_back(v);
		}
	}
	for(int i=1;i<=n;i++){
		if(b[i]) cout<<0<<' ';
		else cout<<min(d[i*4+3],d[i*4+4])<<' ';
	}
}

评论

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

正在加载评论...