开学测试2018.9.1周年纪念日 BSOJ

描述
20180901105217_44309
输入
20180901105240_82789
输出
20180901105258_73744
样例输入[复制]
5 7
3
2
2
1
4
1 5 1
1 3 7
2 1 4
2 3 6
3 4 5
2 4 3
5 4 2
样例输出[复制]
11 5
5 29
 
 
 
第一个问题显然是最小生成树,直接上板子就可以了
第二个问题稍微要复杂一点
首先他是要求一个最小值,我们再来看数据范围发现非常大,n是1e6,如果直接进行暴力的后果是不可想象的
我们推算一下只有n与nlogn可以符合要求
但是nlogn不行因为这道题没有二的性质(如果你非说是二分我也没话可说)
所以只能是线性复杂度
那么这个复杂度我们分析出来了,发现每个点要O(1)递推
自然而然我们想到一个递推的方法
 

观察这个图,显然我们只能一个一个往下递推

对于x的总值h[x]我们已经算了出来

如果现在把重心放在了y会产生什么后果?

对于y及其子树的所有人就会少走d的距离,代价少了d*siz[y]

记所有人数为all,对于除y以外的人,要多走d,代价多了d*(all-siz[y])

就这样我们就实现了O(1)递推

至于那个最开始的值,我们以1为根,进行一次dfs,记录一下每个点到根节点的距离和每个点子树的大小

然后出来就暴力计算h[1]的值

最后比较一下就可以了

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define N 1000006
 5 using namespace std;
 6 long long max0=0,ans=0,fa[N],n,m,p[N],min0=999999999999999999999;
 7 long long cnt,first[N],nxt[N],siz[N],dep[N],h[N],temp,all=0;
 8 struct node{
 9     long long u,v,w;
10 }e[N],g[N];
11 long long find(long long x){
12     if(x!=fa[x])return fa[x]=find(fa[x]);
13     return fa[x];
14 }
15 void merge(long long x,long long y){
16     long long f1=find(x),f2=find(y);
17     if(f1!=f2){
18         fa[f1]=f2;
19     }
20 }
21 void add(long long u,long long v,long long w){
22     e[++cnt].u=u;
23     e[cnt].v=v;
24     e[cnt].w=w;
25     nxt[cnt]=first[u];
26     first[u]=cnt;
27 }
28 void kruskal(){
29     long long tot=0;
30     for(long long i=1;i<=m;i++){
31         long long u=g[i].u,v=g[i].v;
32         if(find(u)!=find(v)){
33             merge(u,v);
34             add(u,v,g[i].w);
35             add(v,u,g[i].w);
36             tot++;
37             ans+=g[i].w;
38             max0=max(max0,g[i].w);
39             if(tot==n-1)return;
40         }
41     }
42 }
43 bool cmp(node a,node b){
44     return a.w<b.w;
45 }
46 void dfs(long long x,long long father){
47     siz[x]=p[x];
48     for(long long i=first[x];i;i=nxt[i]){
49         long long v=e[i].v;
50         if(v==father)continue;
51         dep[v]=dep[x]+e[i].w;
52         dfs(v,x);
53         siz[x]+=siz[v];
54     }
55 }
56 void dfs2(long long x,long long father){
57     if(h[x]<min0){
58         min0=h[x];
59         temp=x;
60     }
61     for(long long i=first[x];i;i=nxt[i]){
62         long long v=e[i].v;
63         if(v==father)continue;
64         h[v]=h[x]-siz[v]*e[i].w+(all-siz[v])*e[i].w;
65         dfs2(v,x);
66     }
67 }
68 int main(){
69 //    freopen("anniversary.in","r",stdin);
70 //    freopen("anniversary.out","w",stdout);
71     scanf("%lld%lld",&n,&m);
72     for(long long i=1;i<=n;i++){
73         fa[i]=i;
74         scanf("%lld",&p[i]);
75         all+=p[i];
76     }
77     for(long long i=1;i<=m;i++)scanf("%lld%lld%lld",&g[i].u,&g[i].v,&g[i].w);
78     sort(g+1,g+m+1,cmp);
79     kruskal();
80     cout<<ans<<" "<<max0<<endl;
81     dep[1]=0;
82     dfs(1,0);
83     for(long long i=1;i<=n;i++)
84         h[1]+=dep[i]*p[i];//计算1的总值可以往下递推 
85     dfs2(1,0);
86     cout<<temp<<" "<<min0;
87     return 0;
88 }

注意那个极大值要开的非常大非常大

over,还是很简单的题目,30分钟足矣

猜你喜欢

转载自www.cnblogs.com/saionjisekai/p/9570824.html