Moving to Nuremberg UVA12223

发布时间 2023-04-25 13:15:04作者: towboat

题目大意:给出n,一个无根的树,每条边上都有权值。

现在每个位置都有一个景点,一个人想在一年之内去cnt[ i ] 次景点,所以接下来给出m,表示说在m个位置上有这个人想去的地方,给出位置以及想去的次数(注意,每去一个景点都要返回自己的住处),namo这个人该住在哪里走的路程才最短。

换根dp

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N =1e5,M=N;
#define int long long
const int inf =1e9 ;
 int n,m,f[N],g[N],s[N] ;
 int ans ;
 int nxt[M],go[M],hd[N],all=1,w[M];
 
 void add_(int x,int y,int z){
 	all++;go[all]=y; nxt[all]=hd[x]; hd[x]=all;
 	w[all]=z;
 }
 void clr() {
 	ans=inf;
    memset(s, 0, sizeof s);
    all=1; for (int i= 0;i<=n; i++) hd[i]=0;
 }
 void dfs(int x,int fa){
 	f[x]=0;
 	for(int i=hd[x];i;i=nxt[i]){
 		int y=go[i],z=w[i];  if(fa==y) continue;
 		dfs(y,x); 
 		
 		s[x]+=s[y];
 		f[x]+=f[y]+2*z*s[y] ;
 	}
 }
 void dp(int x,int fa){
 	ans=min(ans,g[x]); 
 	for(int i=hd[x];i;i=nxt[i]){
 		int y=go[i],z=w[i];  if(fa==y) continue;
 		g[y]= g[x]- s[y]*2*z + (s[1]-s[y])*2*z;
 		dp(y,x); 
 	}
 }
 signed main(){
 	int tes;cin>>tes;
 	while(tes--){
	 	cin>>n;
	 	clr();
	 	int x,y,z;
	 	for(int i=1;i<n;i++)
	 		cin>>x>>y>>z,add_(x,y,z),add_(y,x,z);
	 	cin>>m;
	 	for(int i=1;i<=m;i++) 
	 		cin>>x>>z,s[x]=z;
	 		
	 	dfs(1,0); 
	 	g[1]=f[1]; ans=g[1];
	 	dp(1,0);
	 	cout<<ans <<endl; 
	 	
	 	int flg = 0;
        for (int i=1;i<=n;i++) {
            if (g[i] ==ans && !flg) {
                cout<<i;
                flg = 1;
            }
            else if (g[i] ==ans) cout<<' '<<i;
        }
       cout<<endl;
 	}
 }