标签:pre lld continue mes 自己 names nod 没有 div
一道比较经典的题(蒟蒻的我没有一次切掉)……
首先这道题要优化的原因就是数据范围,要是O(n2) “ 显然 ” 会超时。。。
那么我们很不情愿不得已不开心地最终被迫考虑一下优化(说实话好多算法都是为优化而生的啊)。
首先记录所有点(记得点上有可能有好几头牛)到根节点的路径之和。
那么每一次考虑,将汇聚的点从父亲改到现在到的这个儿子,那么,以儿子节点作为根的子树上的所有点,就都少走了从儿子到父亲的距离,那么除这些点以外的点,它们都要多走从儿子到父亲的距离。
那么我们只要一开始随意找一个点作为root,dfs求出距离和,再来一次dfs从下往上不断更新状态就好,每次取最优解就可以了。
我第一次没A是因为在第二次dfs的时候忘了继续往上dfs(我对自己表示emmm……),第二次是因为没开long long……
代码如下(请不要学习黑科技):
#include<cstdio> #include<iostream> #include<cstring> using namespace std; #define maxn 10000005 #define int long long int num[maxn],dis[maxn],head[maxn]; struct node { int to,nxt,w; } e[maxn]; int cnt,tot,n,d,ans; void add(int a,int b,int c) { e[++cnt].to=b; e[cnt].nxt=head[a]; head[a]=cnt; e[cnt].w=c; } void dfs(int u,int fa) { for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if(v==fa) continue; dfs(v,u); num[u]+=num[v]; d+=e[i].w*num[v]; } } void dp(int u,int fa) { for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if(v==fa) continue; dis[v]=dis[u]-num[v]*e[i].w+(tot-num[v])*e[i].w; ans=min(ans,dis[v]); dp(v,u); } } main() { scanf("%lld",&n); for(int i=1;i<=n;i++) { int am; scanf("%lld",&am); num[i]=am; tot+=am; } for(int i=1;i<n;i++) { int a,b,c; scanf("%lld%lld%lld",&a,&b,&c); add(a,b,c); add(b,a,c); } dfs(1,0); dis[1]=d; ans=d; dp(1,0); printf("%lld",ans); return 0; }
P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…
标签:pre lld continue mes 自己 names nod 没有 div
原文地址:https://www.cnblogs.com/popo-black-cat/p/10206416.html