开学测试2018.9.1周年纪念日 BSOJ
描述
输入
输出
第一个问题显然是最小生成树,直接上板子就可以了
第二个问题稍微要复杂一点
首先他是要求一个最小值,我们再来看数据范围发现非常大,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分钟足矣