2021.08.09 P6037 Ryoku的探索(基环树)

2021.08.09 P6037 Ryoku的探索(基环树)

P6037 Ryoku 的探索 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

重点:

1.树的性质

2.基环树的性质

题意:

Ryoku 所处的世界可以抽象成一个有 nn 个点, nn 条边的带权无向连通图 GG。每条边有美观度和长度。

Ryoku 会使用这样一个策略探索世界:在每个点寻找一个端点她未走过的边中美观度最高的走,如果没有边走,就沿着她前往这个点的边返回,类似于图的深度优先遍历

探索的一个方案的长度是这个方案所经过的所有边长度的和(返回时经过的长度不用计算)。

她想知道,对于每一个起点 s=1,2,⋯,n,她需要走过的长度是多少?

分析及代码:

//这是一棵美丽的基环树。
//先思考只是一棵树的情况:遍历所有边
//如果是一棵有x个点在环上的基环树呢?
//先从根结点出发,肯定要遍历子树
//接着访问环上左右两个边中最美丽的边,一路走到另一边的端点 
//不从根节点出发,那就先遍历子树,走到根节点~
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

typedef long long ll;
const int N=1e6+10;
int n,vis[N],cnt,head[N],ind,dfn[N],root[N],ans[N],fa[N];
ll sum;
struct node{
	int to,next,val,beauty;
}a[N<<1];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v,int w,int x){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].beauty=x;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline void find(int x){
	++ind;
	dfn[x]=ind;
	for(int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(v==fa[x])continue;
		if(dfn[v]){
			if(dfn[v]<dfn[x])continue;
			vis[v]=1;
			while(v!=x)vis[fa[v]]=1,v=fa[v];
		}else{
			fa[v]=x;
			find(v);
		}
	}
}
void dfs(int x,int rt){
	fa[x]=rt;
	root[x]=1;
	for(int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(root[v]||vis[v])continue;
		dfs(v,rt);
	}
}

int main(){
	n=read();
	for(int i=1;i<=n;i++){
		int u,v,w,x;
		u=read();v=read();w=read();x=read();
		add(u,v,w,x);add(v,u,w,x);
		sum+=w;
	}
	find(1);
	for(int i=1;i<=n;i++){
		if(vis[i]){
			dfs(i,i);
			int minn=0x3f3f3f3f;
			for(int j=head[i];j;j=a[j].next){
				int v=a[j].to;
				if(vis[v]&&a[j].beauty<minn)ans[i]=a[j].val,minn=a[j].beauty;
			}
		}
	}
	for(int i=1;i<=n;i++)cout<<sum-1ll*ans[fa[i]]<<endl;
	return 0;
}
上一篇:P3387 缩点


下一篇:【Nowcoder】2021牛客暑假集训营(第六场): Defend Your Country 判割点