poj1935
这道题看起来虽然像个树形dp,但是仔细观察其性质之后发现不用这么复杂,只要将这棵树上存在要去的点的子树都留下,将整张图的边权加起来*2之后减去一条根到叶子节点的最长路径即可
下附代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 int Next[100005],to[100005]; 7 ll len[100005],head[50005],tot=0; 8 ll a[50005],flag[50005],dp[50005],de,sum; 9 int n,k,m; 10 void add(int a,int b,int c){ 11 Next[tot]=head[a],to[tot]=b,len[tot]=c; 12 head[a]=tot++; 13 } 14 void find(int x,int pre){ 15 ll bb=0,ret=a[x]; 16 for (int i=head[x]; i!=-1; i=Next[i]){ 17 int v=to[i]; 18 if (v!=pre){ 19 find(v,x); 20 bb=1; 21 ret=ret|flag[v]; 22 } 23 } 24 flag[x]=ret; 25 } 26 void dfs(int x,int pre){ 27 ll maxn=0; 28 for (int i=head[x]; i!=-1; i=Next[i]){ 29 int v=to[i]; 30 if (v!=pre){ 31 if (flag[v]) { 32 dfs(v,x); 33 maxn=max(maxn,len[i]); 34 dp[x]+=dp[v]+len[i]*2; 35 } 36 } 37 } 38 } 39 void sol(int x,int pre){ 40 for (int i=head[x]; i!=-1; i=Next[i]){ 41 int v=to[i]; 42 if (v!=pre){ 43 if (flag[v]){ 44 sum+=len[i]; 45 sol(v,x); 46 sum-=len[i]; 47 } 48 } 49 } 50 de=max(de,sum); 51 } 52 int main(){ 53 while (scanf("%d%d",&n,&k)!=EOF){ 54 memset(dp,0,sizeof(dp)); 55 memset(a,0,sizeof(a)); 56 for (int i=1; i<=n; i++) 57 head[i]=-1; 58 for (int i=1; i<n; i++){ 59 int a,b,c; 60 scanf("%d%d%d",&a,&b,&c); 61 add(a,b,c); 62 add(b,a,c); 63 } 64 scanf("%d",&m); 65 for (int i=1; i<=m; i++){ 66 int x; 67 scanf("%d",&x); 68 a[x]=1; 69 } 70 find(k,-1); 71 dfs(k,-1); 72 sum=0; 73 de=0; 74 sol(k,-1); 75 printf("%lld\n",dp[k]-de); 76 } 77 return 0; 78 }