![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define MAXN 200005 using namespace std; long long n,tot; long long f[MAXN],cnt[MAXN],ans[MAXN]; struct node{ long long from,to,cost,next,tp; }e[MAXN<<1]; void init(){ tot=0; memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++)f[i]=i,cnt[i]=1; } void add(long long x,long long y,long long z){ tot++; e[tot].from=x; e[tot].to=y; e[tot].cost=z; } long long found(long long x){ if(f[x]==x)return x; int fa=found(f[x]); f[x]=fa; return fa; } bool cmp(node x,node y){ return x.cost>y.cost; } int main(){ while(scanf("%lld",&n)==1){ init(); for(int i=1;i<n;i++){ long long x,y,z; scanf("%lld%lld%lld",&x,&y,&z); add(x,y,z); } sort(e+1,e+1+tot,cmp); for(int i=1;i<n;i++){ long long ff=found(e[i].from),fy=found(e[i].to); if(ff!=fy){ if(ans[fy]+cnt[ff]*e[i].cost>ans[ff]+cnt[fy]*e[i].cost)swap(ff,fy); ans[ff]+=(cnt[fy]*e[i].cost); cnt[ff]+=cnt[fy]; f[fy]=ff; } } cout<<ans[found(1)]<<endl; } }
一开始有点想法....
..................
嘛,仔细分析一下,发现可以在最小值最大哪里搞一下.....
尝试从小到大枚举每条边....发现这样答案可以计算(就是一个分治的过程....每次选择与这条边相连的两点(怎么说呢)就是舍去一段子树....差不多了吧)
或者贪心好像也行把....每次把节点数小的给删掉....(显然满足题目要求把....).
然后考虑怎么解决一条边是否已经再被删掉的子树里面出现....
直接并查集维护一下每个边左右子树的根....要删掉那一个就把它的根标记一下就好了.....但是不能路径压缩,,,,(显然把....)
但是,,上面做法会t飞
于是乎,再度分析...
不如从最大值考虑?
于是乎,,,,,,发现,一些较大边对于答案没有贡献啊!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
那么我们要它干嘛,直接删掉.....考虑删掉后咋办....把两个点合并呗.....
对于没有贡献的边怎么合并都无所谓啦......
但是对于有贡献的就要考虑,既然是要最大化答案,,,,,当然是按照可以使得答案最大的来搞(感觉自己好多废话)
于是乎就清晰了
1 从大到小排序
2 然后依次合并点集....
然后这题就结束了
------------------------------------------------------------------------------------------------------------------------------------------------------------
经验:
1 仔细分析题目啊!!!!!!!
2 遇到难搞(会炸)的地方要考虑影藏性质
3.不能应为感觉思考出一个假的正解(没AC)就沾沾自喜 去颓