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; }