树形dp系列

hdu 1520,poj2342

Anniversary party

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 12664    Accepted Submission(s): 5106


Problem Description
There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests' conviviality ratings.
 
Input
Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go T lines that describe a supervisor relation tree. Each line of the tree specification has the form:
L K
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line
0 0
 
Output
Output should contain the maximal sum of guests' ratings.
 
Sample Input
7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0
 
有搞并查集的,麻烦了。树形dp就行了。
当前点有两个状态,一个是去dp[u][1]一个不去dp[u][0]。
所以dp[u][1]=dp[uson1][0]+dp[uson2][0]+...dp[usonn][0] uson是u的孩子。
dp[u][0]=max(dp[uson1][0],dp[uson1][1])+max(dp[uson2][0],dp[uson2][1])+...max(dp[usonn][0],dp[usonn][1]),同样的概念。
难的是杭电的读入会坑人。
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define clr(x) memset(x,0,sizeof(x))
 6 #define clr_1(x) memset(x,-1,sizeof(x))
 7 using namespace std;
 8 const int N=1e4+10;
 9 struct edg
10 {
11     int next,to;
12 }edge[N*2];
13 int head[N],ecnt;
14 int dp[N][2],value[N],fa[N];
15 void addedge(int u,int v)
16 {
17     edge[++ecnt]=(edg){head[u],v};
18     head[u]=ecnt;
19     return ;
20 }
21 void dfs(int u,int pre)
22 {
23     dp[u][0]=dp[u][1]=0;
24     for(int i=head[u];i!=-1;i=edge[i].next)
25     {
26         if(edge[i].to!=pre)
27         {
28             dfs(edge[i].to,u);
29             dp[u][0]+=max(dp[edge[i].to][1],dp[edge[i].to][0]);
30             dp[u][1]+=dp[edge[i].to][0];
31         }
32     }
33     dp[u][1]+=value[u];
34     return ;
35 }
36 int main()
37 {
38     int n,u,v,root,m;
39     while(scanf("%d",&n)!=EOF && n)
40     {
41         for(int i=1;i<=n;i++)
42             scanf("%d",&value[i]);
43         clr_1(head);
44         ecnt=0;
45         clr(fa);
46         while(scanf("%d%d",&u,&v) && u|v)
47         {
48             addedge(v,u);
49             addedge(u,v);
50             fa[u]=v;
51         }
52         for(int i=1;i<=n;i++)
53             if(fa[i]==0)
54             {
55                 root=i;
56                 break;
57             }
58         dfs(root,0);
59         printf("%d
",max(dp[root][0],dp[root][1]));
60     }
61     return 0;
62 }
View Code
 hdu 2196

Computer

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 31015    Accepted Submission(s): 3902


Problem Description
A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information.


Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.
 

Input
Input file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.
 

Output
For each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).
 

Sample Input
5 1 1 2 1 3 1 1 1
 

Sample Output
3 2 3 4 4
 

Author
scnu

树形dp。首先dfs一遍求每个节点的子树内的最长以及次长链并记录该节点最长链链向的子节点。然后第二次dfs比较该节点父亲节点过来的不经过该节点的最长链的长度和该节点最长链的长度,较大者为该节点最长的距离。其中记录最长链链向的子节点是为了第二遍dfs时,防止父结点传向该子节点时选取的链长度为从该子节点出来的链的长度。这种情况下选取的最大的链长不能是从父亲节点传来的链的长度和第二长链的长度。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=1e4+10;
 8 struct edg
 9 {
10     int next,to,cost;
11 }edge[N*2];
12 int head[N],ecnt,allmax[N],maxpt[N],pt[N],maxptsec[N];
13 void addedge(int u,int v,int cost)
14 {
15     edge[++ecnt]=(edg){head[u],v,cost};
16     head[u]=ecnt;
17     return ;
18 }
19 int n,m,k,p,l;
20 void dfs1(int u,int pre)
21 {
22     maxpt[u]=maxptsec[u]=0;
23     pt[u]=0;
24     for(int i=head[u];i!=-1;i=edge[i].next)
25         if(edge[i].to!=pre)
26         {
27             dfs1(edge[i].to,u);
28             if(maxpt[edge[i].to]+edge[i].cost>maxpt[u])
29             {
30                 maxpt[u]=maxpt[edge[i].to]+edge[i].cost;
31                 pt[u]=edge[i].to;
32             }
33         }
34     for(int i=head[u];i!=-1;i=edge[i].next)
35         if(edge[i].to!=pre)
36         {
37             if(maxpt[edge[i].to]+edge[i].cost>maxptsec[u] && pt[u]!=edge[i].to)
38             {
39                 maxptsec[u]=maxpt[edge[i].to]+edge[i].cost;
40             }
41         }
42     return ;
43 }
44 void dfs2(int u,int pre,int ans)
45 {
46     allmax[u]=max(ans,maxpt[u]);
47     if(ans>=maxpt[u])
48     {
49         for(int i=head[u];i!=-1;i=edge[i].next)
50         {
51             if(edge[i].to!=pre)
52             {
53                 dfs2(edge[i].to,u,ans+edge[i].cost);
54             }
55         }
56     }
57     else
58     {
59          for(int i=head[u];i!=-1;i=edge[i].next)
60         {
61             if(edge[i].to!=pre)
62             {
63                 if(pt[u]==edge[i].to)
64                     dfs2(edge[i].to,u,max(ans,maxptsec[u])+edge[i].cost);
65                 else
66                     dfs2(edge[i].to,u,maxpt[u]+edge[i].cost);
67             }
68         }
69     }
70     return ;
71 }
72 int main()
73 {
74     while(scanf("%d",&n)!=EOF)
75     {
76         clr_1(head);
77         ecnt=0;
78         for(int i=2;i<=n;i++)
79         {
80             scanf("%d%d",&m,&k);
81             addedge(i,m,k);
82             addedge(m,i,k);
83         }
84         allmax[0]=0;
85         dfs1(1,1);
86         dfs2(1,1,0);
87         for(int i=1;i<=n;i++)
88             printf("%d
",allmax[i]);
89     }
90     return 0;
91 }
View Code
vijos p1518

描述

几乎整个Byteland 王国都被森林和河流所覆盖。小点的河汇聚到一起,形成了稍大点的河。就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海。这条大河的入海口处有一个村庄——Bytetown。

在Byteland国,有n个伐木的村庄,这些村庄都座落在河边。目前在Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料。木料被砍下后,顺着河流而被运到Bytetown的伐木场。Byteland 的国王决定,为了减少运输木料的费用,再额外地建造k个伐木场。这k个伐木场将被建在其他村庄里。这些伐木场建造后,木料就不用都被送到Bytetown了,它们可以在 运输过程中第一个碰到的新伐木场被处理。显然,如果伐木场座落的那个村子就不用再付运送木料的费用了。它们可以直接被本村的伐木场处理。

注:所有的河流都不会分叉,形成一棵树,根结点是Bytetown。

国王的大臣计算出了每个村子每年要产多少木料,你的任务是决定在哪些村子建设伐木场能获得最小的运费。其中运费的计算方法为:每一吨木料每千米1分钱。

编一个程序: 
1.从文件读入村子的个数,另外要建设的伐木场的数目,每年每个村子产的木料的块数以及河流的描述。 
2.计算最小的运费并输出。

格式

输入格式

第一行包括两个数n(2<=n<=100),k(1<=k<=50,且k<=n)。n为村庄数,k为要建的伐木场的数目。除了Bytetown 外,每个村子依次被命名为 1,2,3……n,Bytetown被命名为0。

接下来n行,每行3个整数:
wi——每年 i 村子产的木料的块数。(0<=wi<=10000) 
vi——离 i 村子下游最近的村子。(即 i 村子的父结点)(0<=vi<=n) 
di——vi 到 i 的距离(千米)。(1<=di<=10000) 
保证每年所有的木料流到bytetown 的运费不超过2000,000,000分 
50%的数据中n不超过20。

输出格式

输出最小花费,精确到分。

样例1

样例输入1

4 2 
1 0 1 
1 1 10 
10 2 5 
1 2 3 

样例输出1

4
 
论文题,详解见陈瑜希的《多角度思考 创造型思维》。不过数据量做了微小的改动,为了好写点并且记录方便,转为二叉做法而不是背包做法。理论上两者时间效率差不多。这题要先把多叉转二叉。这个用链式前向星就能实现。然后记忆化搜索答案可以少搜索很多状态以及去掉重复状态的搜索,比背包好点。当然要适当剪枝,其中一个剪枝点就是当前可建伐木场数k>=该节点的子树的节点数目,这时候肯定是0直接返回。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define LL long long
 5 #define mod 1000000007
 6 using namespace std;
 7 const int N=2e2+10;
 8 int f[N][N][N],fa[N];
 9 int dis[N],ans;
10 struct edg
11 {
12     int next,to,val;
13 }edge[N*2];
14 int head[N],ecnt,sonnum[N];
15 int w[N],n,m,k,t,l,v;
16 void addedge(int u,int v,int val)
17 {
18     edge[++ecnt]=(edg){head[u],v,val};
19     head[u]=ecnt;
20     return ;
21 }
22 void dfs1(int u,int pre,int dist)
23 {
24     dis[u]=dist;
25     fa[u]=pre;
26     if(head[u]!=-1 && edge[head[u]].to==pre)
27         head[u]=edge[head[u]].next;
28     for(int i=head[u];i!=-1;i=edge[i].next)
29     {
30         if(edge[i].next!=-1 && edge[edge[i].next].to==pre)
31             edge[i].next=edge[edge[i].next].next;
32         dfs1(edge[i].to,u,dist+edge[i].val);
33     }
34     return ;
35 }
36 int findson(int u,int i)
37 {
38     sonnum[u]=0;
39     sonnum[u]+=((head[u]==-1)?0:findson(edge[head[u]].to,head[u]));
40     sonnum[u]+=((edge[i].next==-1)?0:findson(edge[edge[i].next].to,edge[i].next));
41     return sonnum[u]+1;
42 }
43 int dfs2(int u,int to,int pk,int i)
44 {
45     if(f[u][to][pk]!=-1) return f[u][to][pk];
46     if(pk>sonnum[u]) return 0;
47     int ans=-1;
48     int brother,son;
49     //不选u,0点也包括因为他也不建伐木场。
50     for(int j=0;j<=pk;j++)
51     {
52         son=(head[u]==-1)?0:dfs2(edge[head[u]].to,to,j,head[u]);
53         brother=(edge[i].next==-1)?0:dfs2(edge[edge[i].next].to,to,pk-j,edge[i].next);
54         if(ans==-1||ans>son+brother)
55             ans=son+brother;
56     }
57     if(ans==-1)
58         ans=w[u]*(dis[u]-dis[to]);
59     else
60         ans+=w[u]*(dis[u]-dis[to]);
61     //选u
62     if(pk>0 && u!=0)
63     {
64          for(int j=0;j<pk;j++)
65         {
66             son=(head[u]==-1)?0:dfs2(edge[head[u]].to,u,j,head[u]);
67             brother=(edge[i].next==-1)?0:dfs2(edge[edge[i].next].to,to,pk-j-1,edge[i].next);
68             if(ans>son+brother)
69                 ans=son+brother;
70         }
71     }
72     return f[u][to][pk]=ans;
73 }
74 int main()
75 {
76     scanf("%d%d",&n,&k);
77     clr_1(head);
78     ecnt=0;
79     for(int i=1;i<=n;i++)
80     {
81         scanf("%d%d%d",&w[i],&v,&l);
82         addedge(i,v,l);
83         addedge(v,i,l);
84     }
85     clr(dis);
86     edge[0].next=-1;
87     dfs1(0,0,0);
88     findson(0,0);
89     clr_1(f);
90     printf("%d
",dfs2(0,0,k,0));
91     return 0;
92 }
View Code

codevs 1787

网络收费

 

2006年NOI全国竞赛

 时间限制: 3 s
 空间限制: 128000 KB
 题目等级 : 大师 Master
 
题目描述 Description

网络已经成为当今世界不可或缺的一部分。每天都有数以亿计的人使用网络 进行学习、科研、娱乐等活动。然而,不可忽视的一点就是网络本身有着庞大的 运行费用。所以,向使用网络的人进行适当的收费是必须的,也是合理的。 
MY 市 NS 中学就有着这样一个教育网络。网络中的用户一共有 2N个,编号 依次为 1, 2, 3, …, 2N。这些用户之间是用路由点和网线组成的。用户、路由点与 网线共同构成一个满二叉树结构。树中的每一个叶子结点都是一个用户,每一个 非叶子结点(灰色)都是一个路由点,而每一条边都是一条网线(见下图,用户 结点中的数字为其编号)。

MY 网络公司的网络收费方式比较奇特,称为“ 配对收费 ”。即对于每两个 用户 i, j (1≤i < j ≤2N ) 进行收费。由于用户可以自行选择两种付费方式 A、B 中的一种,所以网络公司向学校收取的费用与每一位用户的付费方式有关。该费 用等于每两位不同用户配对产生费用之和。 
为了描述方便,首先定义这棵网络树上的一些概念: 祖先:根结点没有祖先,非根结点的祖先包括它的父亲以及它的父亲的祖先; 管辖叶结点:叶结点本身不管辖任何叶结点,非叶结点管辖它的左儿子所管 辖的叶结点与它的右儿子所管辖的叶结点; 距离:在树上连接两个点之间的用边最少的路径所含的边数。 
对于任两个用户 i, j (1≤i<j≤2N ),首先在树上找到与它们距离最近的公共 祖先:路由点 P,然后观察 P 所管辖的叶结点(即用户)中选择付费方式 A 与 B 的人数,分别记为 nA 与 nB,接着按照网络管理条例第 X 章第 Y 条第 Z 款进行收费(如下表),其中 Fi, j为 i 和 j 之间的流量,且为已知量。

由于最终所付费用与付费方式有关,所以 NS 中学的用户希望能够自行改变 自己的付费方式以减少总付费。然而,由于网络公司已经将每个用户注册时所选 择的付费方式记录在案,所以对于用户 i,如果他/她想改变付费方式(由 A 改为 B或由 B改为A),就必须支付Ci元给网络公司以修改档案(修改付费方式记录)。 现在的问题是,给定每个用户注册时所选择的付费方式以及 Ci,试求这些用 户应该如何选择自己的付费方式以使得 NS 中学支付给网络公司的总费用最少 (更改付费方式费用+配对收费的费用)。

输入描述 Input Description

输入文件中第一行有一个正整数 N。 第二行有 2N个整数,依次表示 1 号,2 号,…,2N号用户注册时的付费方式, 每一个数字若为 0,则表示对应用户的初始付费方式为 A,否则该数字为 1,表 示付费方式为 B。 第三行有 2N个整数,表示每一个用户修改付费方式需要支付的费用,依次为 C1, C2, …,CM 。( M=2N ) 以下 2N-1 行描述给定的两两用户之间的流量表 F,总第(i + 3)行第 j 列的整 数为 Fi, j+i 。(1≤i<2N,1≤j≤2N – i) 所有变量的含义可以参见题目描述。

输出描述 Output Description

你的程序只需要向输出文件输出一个整数,表示 NS 中学支付给网络公司的 最小总费用。(单位:元)

样例输入 Sample Input

2

1 0 1 0

2 2 10 9 

10 1 2

2 1

3

样例输出 Sample Output

8

数据范围及提示 Data Size & Hint

将 1 号用户的付费方式由 B 改为 A,NS 中学支付给网络公司的费用达到最 小。

40%的数据中 N≤4;

80%的数据中 N≤7;

100%的数据中 N≤10,0≤Fi, j≤500,0≤Ci≤500 000。 


纯论文题,按照论文所说的做,并且加上记忆化搜索,很容易就AC了。小细节看注释。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define clrmax(x) memset(x,0x3f3f3f3f,sizeof(x))
 5 #define mod 1000000007
 6 #define LL long long
 7 using namespace std;
 8 const int maxN=5e3+10;
 9 int f[maxN][maxN];
10 int flow[maxN][maxN];
11 int c[maxN];
12 int cost[maxN][20],fa[maxN][20];
13 bool chose[maxN];
14 int N,n,m,k,ans,p;
15 int dfs(int u,int dep,int sta)//sta前从右往左第dep+1位开始是该结点分配的B方式的数量,1~dep位为其祖先结点na和nb的大小相对关系,表现为B收费为1,A收费为0。
16 {
17     if(f[u][sta]!=0x3f3f3f3f) return f[u][sta];
18     int num=sta>>dep;
19     int fasta=sta^(num<<dep);
20     //该结点的收费选择chos
21     int chos=(1<<(N-dep))-num>=num?1:0;
22     //叶子结点处理返回
23     if(dep==N)
24     {
25         int v=u-(n-1);
26         fasta<<=1;
27         fasta|=chos;
28         if(num^chose[v])
29             f[u][sta]=c[v];
30         else
31             f[u][sta]=0;
32         for(int i=N;i>=0;i--)
33         {
34             if(!((fasta&1)^num))
35                 f[u][sta]+=cost[v][i];
36             fasta>>=1;
37         }
38         return f[u][sta];
39     }
40     //约束左右结点取B的数量在合理范围内,并选择其中最小的一个和。
41     int minx=max(0,num-(1<<N-dep-1));
42     int maxx=min(num,1<<N-dep-1);
43     for(int i=minx;i<=maxx;i++)
44         f[u][sta]=min(dfs(u<<1,dep+1,(i<<dep+1)|(fasta<<1|chos))+dfs(u<<1|1,dep+1,(num-i<<dep+1)|(fasta<<1|chos)),f[u][sta]);
45     return f[u][sta];
46 }
47 int main()
48 {
49     scanf("%d",&N);
50     n=1<<N;
51     for(int i=1;i<=n;i++)
52     {
53         scanf("%d",&p);
54         chose[i]=p;
55     }
56     for(int i=1;i<=n;i++)
57         scanf("%d",&c[i]);
58     for(int i=1;i<=n;i++)
59         for(int j=i+1;j<=n;j++)
60             scanf("%d",&flow[i][j]);
61     //计算子结点i(树上编号为i+n-1)在深度为j的祖先
62     for(int i=1;i<=n;i++)
63     {
64         k=i+n-1;
65         for(int j=N;j>=0;j--)
66         {
67             fa[i][j]=k;
68             k>>=1;
69         }
70     }
71     clr(cost);
72     //若i,j在深度为k处祖先相同,那末将流量费用flow[i,j]加到i和j在深度k所需要的费用中。
73     for(int i=1;i<=n;i++)
74         for(int j=i+1;j<=n;j++)
75             for(int k=N;k>=0;k--)
76                 if(fa[i][k]==fa[j][k])
77                 {
78                     cost[i][k]+=flow[i][j];
79                     cost[j][k]+=flow[i][j];
80                     break;
81                 }
82     clrmax(f);
83     ans=0x3f3f3f3f;
84     for(int i=0;i<=n;i++)
85         ans=min(ans,k=dfs(1,0,i));
86     printf("%d
",ans);
87     return 0;
88 }
View Code

 hdu 4276

The Ghost Blows Light

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3538    Accepted Submission(s): 1128


Problem Description

My name is Hu Bayi, robing an ancient tomb in Tibet. The tomb consists of N rooms (numbered from 1 to N) which are connected by some roads (pass each road should cost some time). There is exactly one route between any two rooms, and each room contains some treasures. Now I am located at the 1st room and the exit is located at the Nth room.
Suddenly, alert occurred! The tomb will topple down in T minutes, and I should reach exit room in T minutes. Human beings die in pursuit of wealth, and birds die in pursuit of food! Although it is life-threatening time, I also want to get treasure out as much as possible. Now I wonder the maximum number of treasures I can take out in T minutes.
 
Input
There are multiple test cases.
The first line contains two integer N and T. (1 <= n <= 100, 0 <= T <= 500)
Each of the next N - 1 lines contains three integers a, b, and t indicating there is a road between a and b which costs t minutes. (1<=a<=n, 1<=b<=n, a!=b, 0 <= t <= 100)
The last line contains N integers, which Ai indicating the number of treasure in the ith room. (0 <= Ai <= 100)
 
Output
For each test case, output an integer indicating the maximum number of treasures I can take out in T minutes; if I cannot get out of the tomb, please output "Human beings die in pursuit of wealth, and birds die in pursuit of food!".
 
Sample Input
5 10 1 2 2 2 3 2 2 5 3 3 4 3 1 2 3 4 5
 
Sample Output
11
 
如byteland的做法,多叉转二叉后对时间进行分配,分配给该结点的子树和他兄弟所在的子树。并记忆化搜索,时间效率还是很高的,比树上背包高那么一丢丢。
我们设置f[u][t]为从u点和其兄弟结点出发最终回到这些节点耗费时间t所能得到的最大财宝价值。所以f[u][t]=max {max{ f[left][k-time]+treasure[u]+f[right][k-u-time] } , f[right][t] },time为链向该点边的边权*2,left为该点孩子,right为该点兄弟。treasure[u]为宝藏价值即点权。k为对该部分分配的时间。
如果选择u所在的子树,则需要减去链向u的边的边权(时间*2),如果选择其兄弟结点则直接选择不需要减去边权(因为递归到兄弟结点,兄弟结点会自行选择是否选择他自己)。这样进行一个时间分配的dfs就能得出结果。但是由于我们一定要走1~n的路径,所以先把1~n的点权赋为0,边权赋为0,再做这个树形dp。
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define mod 1000000007
 5 #define LL long long
 6 using namespace std;
 7 const int maxT=5e2+10;
 8 const int maxN=1e2+10;
 9 int f[maxN][maxT];
10 struct edg
11 {
12     int next,to,val;
13 }edge[maxN*2];
14 int head[maxN],ecnt;
15 void addedge(int u,int v,int val)
16 {
17     edge[++ecnt]=(edg){head[u],v,val};
18     head[u]=ecnt;
19     return ;
20 }
21 int n,t,tre[maxN],u,v,cost,alltre,flag;
22 bool dfs1(int u,int pre,int dist)
23 {
24     bool p=0,q;
25     if(u==n) p=1;
26     if(u==n && dist>t)
27         flag=-1;
28     if(u==n && dist<=t)
29         flag=dist;
30     if(head[u]!=-1 &&edge[head[u]].to==pre)
31         head[u]=edge[head[u]].next;
32     for(int i=head[u];i!=-1;i=edge[i].next)
33     {
34         if(edge[i].next!=-1 &&edge[edge[i].next].to==pre)
35             edge[i].next=edge[edge[i].next].next;
36         q=dfs1(edge[i].to,u,edge[i].val+dist);
37         if(q)
38             edge[i].val=0;
39         p|=q;
40     }
41     if(p)
42     {
43         alltre+=tre[u];
44         tre[u]=0;
45     }
46     return p;
47 }
48 int dfs2(int u,int t,int i)
49 {
50     if(f[u][t]!=-1) return f[u][t];
51     f[u][t]=0;
52     //只选兄弟
53     f[u][t]=max(f[u][t],edge[i].next==-1?0:dfs2(edge[edge[i].next].to,t,edge[i].next));
54     //选兄弟和自己的子树
55     int tt=t-2*edge[i].val;
56     if(tt>=0)
57     {
58         for(int j=0;j<=tt;j++)
59             f[u][t]=max(f[u][t],(head[u]==-1?0:dfs2(edge[head[u]].to,j,head[u]))+tre[u]+(edge[i].next==-1?0:dfs2(edge[edge[i].next].to,tt-j,edge[i].next)));
60     }
61     return f[u][t];
62 }
63 int main()
64 {
65     while(scanf("%d%d",&n,&t)!=EOF)
66     {
67         clr_1(head);
68         ecnt=0;
69         clr_1(f);
70         alltre=0;
71         for(int i=1;i<n;i++)
72         {
73             scanf("%d%d%d",&u,&v,&cost);
74             addedge(u,v,cost);
75             addedge(v,u,cost);
76         }
77         for(int i=1;i<=n;i++)
78             scanf("%d",&tre[i]);
79         dfs1(1,1,0);
80         if(flag==-1)
81         {
82             printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!
");
83             continue;
84         }
85         edge[0].next=-1;
86         edge[0].val=0;
87         printf("%d
",alltre+dfs2(1,t-flag,0));
88     }
89     return 0;
90 }
View Code
 codeforces 219D
D. Choosing Capital for Treeland
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

The country Treeland consists of n cities, some pairs of them are connected with unidirectional roads. Overall there are n - 1 roads in the country. We know that if we don't take the direction of the roads into consideration, we can get from any city to any other one.

The council of the elders has recently decided to choose the capital of Treeland. Of course it should be a city of this country. The council is supposed to meet in the capital and regularly move from the capital to other cities (at this stage nobody is thinking about getting back to the capital from these cities). For that reason if city a is chosen a capital, then all roads must be oriented so that if we move along them, we can get from city a to any other city. For that some roads may have to be inversed.

Help the elders to choose the capital so that they have to inverse the minimum number of roads in the country.

Input

The first input line contains integer n (2 ≤ n ≤ 2·105) — the number of cities in Treeland. Next n - 1 lines contain the descriptions of the roads, one road per line. A road is described by a pair of integers si, ti (1 ≤ si, ti ≤ nsi ≠ ti) — the numbers of cities, connected by that road. The i-th road is oriented from city si to city ti. You can consider cities in Treeland indexed from 1 to n.

Output

In the first line print the minimum number of roads to be inversed if the capital is chosen optimally. In the second line print all possible ways to choose the capital — a sequence of indexes of cities in the increasing order.

Examples
input
3
2 1
2 3
output
0
2
input
4
1 4
2 4
3 4
output
2
1 2 3

emm算水题吧。先统计下以1为子树要改造多少条路才能做首都。然后对每个点做首都计算其相对于1的改造数量。我们可以发现,每个点为根和以1为根要改造的道路不同之处在于从根到这个点的路上的道路全取反。也就是在这条路上要改造的变为不改造,不改造的变为改造。因此每个点相对改造数量在一遍dfs的时候都能求出来,记录下来在f[i]中。以上两个步骤能在一个dfs中完成。然后查找f[i]中最小值加上1需要改造的道路数就是答案。

 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define mod 1000000007
 5 #define LL long long
 6 using namespace std;
 7 const int N=2e5+10;
 8 struct edg
 9 {
10     int next,to;
11     bool val;
12 }edge[N*2];
13 int head[N],ecnt,n,m,k,t,minx,u,v,all;
14 int f[N];
15 void addedge(int u,int v,bool val)
16 {
17     edge[++ecnt]=(edg){head[u],v,val};
18     head[u]=ecnt;
19     return ;
20 }
21 void init()
22 {
23     clr_1(head);
24     ecnt=0;
25     minx=0x3f3f3f3f;
26     all=0;
27     return ;
28 }
29 void dfs(int u,int pre,int val)
30 {
31     if(val<minx)
32         minx=val;
33     f[u]=val;
34     for(int i=head[u];i!=-1;i=edge[i].next)
35         if(pre!=edge[i].to)
36         {
37             if(!edge[i].val)
38                 all++;
39             dfs(edge[i].to,u,edge[i].val?val+1:val-1);
40         }
41     return ;
42 }
43 int main()
44 {
45     scanf("%d",&n);
46     init();
47     for(int i=1;i<n;i++)
48     {
49         scanf("%d%d",&u,&v);
50         addedge(u,v,true);
51         addedge(v,u,false);
52     }
53     dfs(1,1,0);
54     printf("%d
",all+minx);
55     for(int i=1;i<=n;i++)
56         if(f[i]==minx)
57             printf("%d ",i);
58     printf("
");
59     return 0;
60 }
View Code

poj 3107

Godfather
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 7627   Accepted: 2691

Description

Last years Chicago was full of gangster fights and strange murders. The chief of the police got really tired of all these crimes, and decided to arrest the mafia leaders.

Unfortunately, the structure of Chicago mafia is rather complicated. There are n persons known to be related to mafia. The police have traced their activity for some time, and know that some of them are communicating with each other. Based on the data collected, the chief of the police suggests that the mafia hierarchy can be represented as a tree. The head of the mafia, Godfather, is the root of the tree, and if some person is represented by a node in the tree, its direct subordinates are represented by the children of that node. For the purpose of conspiracy the gangsters only communicate with their direct subordinates and their direct master.

Unfortunately, though the police know gangsters’ communications, they do not know who is a master in any pair of communicating persons. Thus they only have an undirected tree of communications, and do not know who Godfather is.

Based on the idea that Godfather wants to have the most possible control over mafia, the chief of the police has made a suggestion that Godfather is such a person that after deleting it from the communications tree the size of the largest remaining connected component is as small as possible. Help the police to find all potential Godfathers and they will arrest them.

Input

The first line of the input file contains n — the number of persons suspected to belong to mafia (2 ≤ n ≤ 50 000). Let them be numbered from 1 to n.

The following n − 1 lines contain two integer numbers each. The pair aibi means that the gangster ai has communicated with the gangster bi. It is guaranteed that the gangsters’ communications form a tree.

Output

Print the numbers of all persons that are suspected to be Godfather. The numbers must be printed in the increasing order, separated by spaces.

Sample Input

6
1 2
2 3
2 5
3 4
3 6

Sample Output

2 3

求结点u为根的树中,它的子节点的子树中结点数量最大的最小的,并输出这样的结点u。水题,无需赘言。
 1 //#include<bits/stdc++.h>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstring>
 6 #define clr(x) memset(x,0,sizeof(x))
 7 #define clr_1(x) memset(x,-1,sizeof(x))
 8 #define mod 1000000007
 9 #define LL long long
10 using namespace std;
11 const int N=2e5+10;
12 struct edg
13 {
14     int next,to;
15 }edge[N*2];
16 int head[N],ecnt,n,m,k,t,u,v,rmin;
17 int f[N],son[N];
18 void addedge(int u,int v)
19 {
20     edge[++ecnt]=(edg){head[u],v};
21     head[u]=ecnt;
22     return ;
23 }
24 void init()
25 {
26     clr_1(head);
27     ecnt=0;
28     rmin=0x3f3f3f3f;
29     return ;
30 }
31 void dfs(int u,int pre)
32 {
33     int minx=0;
34     son[u]=1;
35     for(int i=head[u];i!=-1;i=edge[i].next)
36         if(pre!=edge[i].to)
37         {
38             dfs(edge[i].to,u);
39             son[u]+=son[edge[i].to];
40             minx=max(son[edge[i].to],minx);
41         }
42     minx=max(minx,n-son[u]);
43     f[u]=minx;
44     rmin=min(rmin,minx);
45     return ;
46 }
47 int main()
48 {
49     scanf("%d",&n);
50     init();
51     for(int i=1;i<n;i++)
52     {
53         scanf("%d%d",&u,&v);
54         addedge(u,v);
55         addedge(v,u);
56     }
57     dfs(1,1);
58     for(int i=1;i<=n;i++)
59         if(f[i]==rmin)
60             printf("%d ",i);
61     printf("
");
62     return 0;
63 }
View Code

poj 3140

Contestants Division
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 10726   Accepted: 3012

Description

In the new ACM-ICPC Regional Contest, a special monitoring and submitting system will be set up, and students will be able to compete at their own universities. However there’s one problem. Due to the high cost of the new judging system, the organizing committee can only afford to set the system up such that there will be only one way to transfer information from one university to another without passing the same university twice. The contestants will be divided into two connected regions, and the difference between the total numbers of students from two regions should be minimized. Can you help the juries to find the minimum difference?

Input

There are multiple test cases in the input file. Each test case starts with two integers N and M, (1 ≤ N ≤ 100000, 1 ≤ M ≤ 1000000), the number of universities and the number of direct communication line set up by the committee, respectively. Universities are numbered from 1 to N. The next line has N integers, the Kth integer is equal to the number of students in university numbered K. The number of students in any university does not exceed 100000000. Each of the following M lines has two integers st, and describes a communication line connecting university s and university t. All communication lines of this new system are bidirectional.

N = 0, M = 0 indicates the end of input and should not be processed by your program.

Output

For every test case, output one integer, the minimum absolute difference of students between two regions in the format as indicated in the sample output.

Sample Input

7 6
1 1 1 1 1 1 1
1 2
2 7
3 7
4 6
6 2
5 7
0 0

Sample Output

Case 1: 1

emmm水题。
 1 //#include<bits/stdc++.h>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstring>
 6 #define clr(x) memset(x,0,sizeof(x))
 7 #define clr_1(x) memset(x,-1,sizeof(x))
 8 #define mod 1000000007
 9 #define LL long long
10 using namespace std;
11 const int N=1e5+10;
12 struct edg
13 {
14     int next,to;
15 }edge[N*2];
16 int head[N],ecnt,n,m,k,t,u,v,pos;
17 LL all,rmin;
18 LL stu[N],son[N],f[N];
19 inline LL labs(LL x)
20 {
21     return x<0?-x:x;
22 }
23 void addedge(int u,int v)
24 {
25     edge[++ecnt]=(edg){head[u],v};
26     head[u]=ecnt;
27     return ;
28 }
29 void init()
30 {
31     clr_1(head);
32     ecnt=0;
33     all=0;
34     rmin=1e17;
35     return ;
36 }
37 void dfs(int u,int pre)
38 {
39     son[u]=stu[u];
40     for(int i=head[u];i!=-1;i=edge[i].next)
41         if(pre!=edge[i].to)
42         {
43             dfs(edge[i].to,u);
44             son[u]+=son[edge[i].to];
45         }
46     f[u]=labs(all-son[u]-son[u]);
47     if(f[u]<rmin)
48         rmin=f[u];
49     return ;
50 }
51 int main()
52 {
53     int kase=0;
54     while(scanf("%d%d",&n,&m) && n||m)
55     {
56         init();
57         for(int i=1;i<=n;i++)
58         {
59             scanf("%lld",&stu[i]);
60             all+=stu[i];
61         }
62         for(int i=1;i<=m;i++)
63         {
64             scanf("%d%d",&u,&v);
65             addedge(u,v);
66             addedge(v,u);
67         }
68         dfs(1,1);
69         printf("Case %d: %lld
",++kase,rmin);
70     }
71     return 0;
72 }
View Code

 poj 2378

Tree Cutting
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 4846   Accepted: 2965

Description

After Farmer John realized that Bessie had installed a "tree-shaped" network among his N (1 <= N <= 10,000) barns at an incredible cost, he sued Bessie to mitigate his losses. 

Bessie, feeling vindictive, decided to sabotage Farmer John's network by cutting power to one of the barns (thereby disrupting all the connections involving that barn). When Bessie does this, it breaks the network into smaller pieces, each of which retains full connectivity within itself. In order to be as disruptive as possible, Bessie wants to make sure that each of these pieces connects together no more than half the barns on FJ. 

Please help Bessie determine all of the barns that would be suitable to disconnect.

Input

* Line 1: A single integer, N. The barns are numbered 1..N. 

* Lines 2..N: Each line contains two integers X and Y and represents a connection between barns X and Y.

Output

* Lines 1..?: Each line contains a single integer, the number (from 1..N) of a barn whose removal splits the network into pieces each having at most half the original number of barns. Output the barns in increasing numerical order. If there are no suitable barns, the output should be a single line containing the word "NONE".

Sample Input

10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8

Sample Output

3
8

水题。
 1 //#include<bits/stdc++.h>
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<cstring>
 5 #define clr(x) memset(x,0,sizeof(x))
 6 #define clr_1(x) memset(x,-1,sizeof(x))
 7 #define LL long long
 8 #define mod 1000000007
 9 using namespace std;
10 const int N=1e4+10;
11 struct edg
12 {
13     int next,to;
14 }edge[2*N];
15 int head[N],ecnt,sonnum[N];
16 bool flag[N];
17 int n,m,t,u,v;
18 void addedge(int u,int v)
19 {
20     edge[++ecnt]=(edg){head[u],v};
21     head[u]=ecnt;
22     return ;
23 }
24 void init()
25 {
26     clr_1(head);
27     ecnt=-1;
28     return ;
29 }
30 void dfs(int u,int pre)
31 {
32     sonnum[u]=1;
33     bool p=1;
34     for(int i=head[u];i!=-1;i=edge[i].next)
35         if(edge[i].to!=pre)
36         {
37             dfs(edge[i].to,u);
38             if(sonnum[edge[i].to]>t)
39                 p=0;
40             sonnum[u]+=sonnum[edge[i].to];
41         }
42     if(n-sonnum[u]>t)
43         p=0;
44     flag[u]=p;
45     return ;
46 }
47 int main()
48 {
49     scanf("%d",&n);
50     init();
51     for(int i=2;i<=n;i++)
52     {
53         scanf("%d%d",&u,&v);
54         addedge(u,v);
55         addedge(v,u);
56     }
57     t=n/2;
58     clr(flag);
59     dfs(1,1);
60     for(int i=1;i<=n;i++)
61     {
62         if(flag[i])
63             printf("%d
",i);
64     }
65     return 0;
66 }
View Code

hdu 3586

Information Disturbing

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 3244    Accepted Submission(s): 1150


Problem Description
In the battlefield , an effective way to defeat enemies is to break their communication system.
The information department told you that there are n enemy soldiers and their network which have n-1 communication routes can cover all of their soldiers. Information can exchange between any two soldiers by the communication routes. The number 1 soldier is the total commander and other soldiers who have only one neighbour is the frontline soldier.
Your boss zzn ordered you to cut off some routes to make any frontline soldiers in the network cannot reflect the information they collect from the battlefield to the total commander( number 1 soldier).
There is a kind of device who can choose some routes to cut off . But the cost (w) of any route you choose to cut off can’t be more than the device’s upper limit power. And the sum of the cost can’t be more than the device’s life m.
Now please minimize the upper limit power of your device to finish your task.
 
Input
The input consists of several test cases.
The first line of each test case contains 2 integers: n(n<=1000)m(m<=1000000).
Each of the following N-1 lines is of the form:
ai bi wi
It means there’s one route from ai to bi(undirected) and it takes wi cost to cut off the route with the device.
(1<=ai,bi<=n,1<=wi<=1000)
The input ends with n=m=0.
 
Output
Each case should output one integer, the minimal possible upper limit power of your device to finish your task.
If there is no way to finish the task, output -1.
 
Sample Input
5 5 1 3 2 1 4 3 3 5 5 4 2 6 0 0
 
Sample Output
3
 

这题的话看到数据范围是n,wi<=1k,那么你心里就应该有点B数了。

对于每个结点我们求出所有切割最大值为p(1≤p≤max(wi))时,其最小的花费。具体为:minx(u,p)=Σminx(v,p)(p<cost),minx(u,p)=min(Σminx(v,p),cost)(p>=cost),,其中cost为切掉u和他父结点之间的边的花费,v为其子节点。这样最多n*max(wi)<=100w的时间复杂度和空间复杂度。其中不存在该最小值的情况置一个大数。然后1号节点中找一个最小符合minx(u,p)<=m的,p即为答案。

 1 //#include<bits/stdc++.h>
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<cstring>
 5 #define clr(x) memset(x,0,sizeof(x))
 6 #define clr_1(x) memset(x,-1,sizeof(x))
 7 #define LL long long
 8 #define mod 1000000007
 9 using namespace std;
10 const int N=1e3+10;
11 struct edg
12 {
13     int next,to,val;
14 }edge[2*N];
15 int head[N],ecnt;
16 LL minx[N][N];
17 int n,m,t,u,v,maxn;
18 void addedge(int u,int v,int val)
19 {
20     edge[++ecnt]=(edg){head[u],v,val};
21     head[u]=ecnt;
22     return ;
23 }
24 void init()
25 {
26     clr_1(head);
27     ecnt=-1;
28     return ;
29 }
30 void dfs(int u,int pre,int cost)
31 {
32     int p;
33     if(edge[head[u]].next==-1 && edge[head[u]].to==pre)
34         for(int i=1;i<=maxn;i++)
35                 minx[u][i]=0x3f3f3f3f;
36     else
37          for(int i=1;i<=maxn;i++)
38                 minx[u][i]=0;
39     for(int i=head[u];i!=-1;i=edge[i].next)
40     {
41         p=edge[i].to;
42         if(p!=pre)
43         {
44             dfs(p,u,edge[i].val);
45             for(int j=1;j<=maxn;j++)
46                 minx[u][j]+=minx[p][j];
47         }
48     }
49     for(int i=cost;i<=maxn;i++)
50         minx[u][i]=min(minx[u][i],(LL)cost);
51 
52 }
53 int flag;
54 int main()
55 {
56     while(scanf("%d%d",&n,&m)!=EOF && (n || m))
57     {
58         init();
59         maxn=0;
60         for(int i=2;i<=n;i++)
61         {
62             scanf("%d%d%d",&u,&v,&t);
63             addedge(u,v,t);
64             addedge(v,u,t);
65             maxn=max(maxn,t);
66         }
67        dfs(1,1,0x3f3f3f3f);
68        flag=0;
69        for(int i=1;i<=maxn;i++)
70         if(minx[1][i]<=(LL)m)
71        {
72             printf("%d
",i);
73             flag=1;
74             break;
75        }
76        if(!flag)
77          printf("-1
");
78     }
79     return 0;
80 }
View Code
Walking Race
Time Limit: 10000MS   Memory Limit: 131072K
Total Submissions: 4217   Accepted: 1047
Case Time Limit: 3000MS

Description

flymouse’s sister wc is very capable at sports and her favorite event is walking race. Chasing after the championship in an important competition, she comes to a training center to attend a training course. The center has N check-points numbered 1 through N. Some pairs of check-points are directly connected by two-way paths. The check-points and the paths form exactly a tree-like structure. The course lasts Ndays. On the i-th day, wc picks check-point i as the starting point and chooses another check-point as the finishing point and walks along the only simple path between the two points for the day’s training. Her choice of finishing point will make it that the resulting path will be the longest among those of all possible choices.

After every day’s training, flymouse will do a physical examination from which data will obtained and analyzed to help wc’s future training be better instructed. In order to make the results reliable, flymouse is not using data all from N days for analysis. flymouse’s model for analysis requires data from a series of consecutive days during which the difference between the longest and the shortest distances wc walks cannot exceed a bound M. The longer the series is, the more accurate the results are. flymouse wants to know the number of days in such a longest series. Can you do the job for him?

Input

The input contains a single test case. The test case starts with a line containing the integers N (N ≤ 106) and M (M < 109). Then follow N − 1 lines, each containing two integers fi and di (i = 1, 2, …, N − 1), meaning the check-points i + 1 and fi are connected by a path of length di.

Output

Output one line with only the desired number of days in the longest series.

Sample Input

3 2
1 1
1 3

Sample Output

3

Hint

Explanation for the sample:

There are three check-points. Two paths of lengths 1 and 3 connect check-points 2 and 3 to check-point 1. The three paths along with wc walks are 1-3, 2-1-3 and 3-1-2. And their lengths are 3, 4 and 4. Therefore data from all three days can be used for analysis.


树形dp参考computer的解法,求的是每个点距离他最远的树上距离。然后对于求出来的答案len[i],用单调队列维护最大值和最小值,即尺取法解决。来找对应的右端点i能取到的最小的左端点j。然后取最大的(i-j+1)即为答案。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #define clr(x) memset(x,0,sizeof(x))
  5 #define clr_1(x) memset(x,-1,sizeof(x))
  6 #define LL long long
  7 #define mod 1000000007
  8 using namespace std;
  9 const int N=1e6+10;
 10 struct edg
 11 {
 12     int next,to;
 13     LL val;
 14 }edge[N*2];
 15 int head[N],ecnt;
 16 LL maxn[N][3];
 17 int pt[N];
 18 int n,p,u,v;
 19 LL len[N];
 20 LL t,m;
 21 struct que
 22 {
 23     int fpt,ept;
 24     int es[N];
 25     void init()
 26     {
 27         fpt=0;
 28         ept=0;
 29         return ;
 30     }
 31     void pop()
 32     {
 33         fpt++;
 34         return ;
 35     }
 36     void popback()
 37     {
 38         ept--;
 39         return ;
 40     }
 41     void push(int x)
 42     {
 43         es[ept++]=x;
 44         return ;
 45     }
 46     int front( )
 47     {
 48         return es[fpt];
 49     }
 50     int back( )
 51     {
 52         return es[ept-1];
 53     }
 54     bool empty( )
 55     {
 56         return fpt==ept;
 57     }
 58 }minx,maxx;
 59 int fminx,fmaxx,maxlong;
 60 void dfs1(int u,int pre)
 61 {
 62     maxn[u][1]=maxn[u][2]=0;
 63     for(int i=head[u];i!=-1;i=edge[i].next)
 64         if(pre!=edge[i].to)
 65         {
 66             dfs1(edge[i].to,u);
 67             if(maxn[edge[i].to][1]+edge[i].val>maxn[u][1])
 68             {
 69                 pt[u]=edge[i].to;
 70                 maxn[u][1]=maxn[edge[i].to][1]+edge[i].val;
 71             }
 72         }
 73     for(int i=head[u];i!=-1;i=edge[i].next)
 74         if(pre!=edge[i].to && pt[u]!=edge[i].to)
 75         {
 76             if(maxn[edge[i].to][1]+edge[i].val>maxn[u][2])
 77             {
 78                 maxn[u][2]=maxn[edge[i].to][1]+edge[i].val;
 79             }
 80         }
 81     return ;
 82 }
 83 void dfs2(int u,int pre,LL maxfa)
 84 {
 85     len[u]=max(maxfa,maxn[u][1]);
 86     for(int i=head[u];i!=-1;i=edge[i].next)
 87         if(pre!=edge[i].to)
 88             if(edge[i].to==pt[u])
 89                 dfs2(edge[i].to,u,max(maxn[u][2],maxfa)+edge[i].val);
 90             else
 91                 dfs2(edge[i].to,u,max(maxn[u][1],maxfa)+edge[i].val);
 92 }
 93 void addedge(int u,int v,LL val)
 94 {
 95     edge[++ecnt]=(edg){head[u],v,val};
 96     head[u]=ecnt;
 97     return ;
 98 }
 99 int main()
100 {
101     scanf("%d%lld",&n,&m);
102     clr_1(head);
103     ecnt=0;
104     for(int i=2;i<=n;i++)
105     {
106         scanf("%d%lld",&v,&t);
107         addedge(i,v,t);
108         addedge(v,i,t);
109     }
110     dfs1(1,1);
111     dfs2(1,1,0);
112 //    for(int i=1;i<=n;i++)
113 //        printf("%d:%lld,%lld,%lld
",i,len[i],maxn[i][1],maxn[i][2]);
114 //    printf("
");
115     maxlong=0;
116     minx.init();
117     maxx.init();
118     fminx=fmaxx=0;
119     for(int i=1;i<=n;i++)
120     {
121         while(!minx.empty() && len[minx.back()]>len[i])
122             minx.popback();
123         minx.push(i);
124         while(!maxx.empty() && len[maxx.back()]<len[i])
125             maxx.popback();
126         maxx.push(i);
127         while(!minx.empty() && !maxx.empty() && (len[maxx.front()]-len[minx.front()]>m))
128             if(maxx.front()>=minx.front())
129             {
130                 fminx=minx.front();
131                 minx.pop();
132             }
133             else
134             {
135                 fmaxx=maxx.front();
136                 maxx.pop();
137             }
138 //            for(int i=minx.fpt;i<minx.ept;i++)
139 //                printf("%d ",minx.es[i]);
140 //            printf("
");
141 //            for(int i=maxx.fpt;i<maxx.ept;i++)
142 //                printf("%d ",maxx.es[i]);
143 //            printf("
");
144 //            printf("%d %d %d
",fminx,fmaxx,i-max(fminx,fmaxx));
145             maxlong=max(i-max(fminx,fmaxx),maxlong);
146     }
147     printf("%d
",maxlong);
148     return 0;
149 }
View Code

hdu 5834

Magic boy Bi Luo with his excited tree

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1485    Accepted Submission(s): 452


Problem Description
Bi Luo is a magic boy, he also has a migic tree, the tree has N nodes , in each node , there is a treasure, it's value is V[i], and for each edge, there is a cost C[i], which means every time you pass the edge i , you need to pay C[i].

You may attention that every V[i] can be taken only once, but for some C[i] , you may cost severial times.

Now, Bi Luo define ans[i] as the most value can Bi Luo gets if Bi Luo starts at node i.

Bi Luo is also an excited boy, now he wants to know every ans[i], can you help him?
 
Input
First line is a positive integer T(T104) , represents there are T test cases.

Four each test:

The first line contain an integer N(N105).

The next line contains N integers V[i], which means the treasure’s value of node i(1V[i]104).

For the next N1 lines, each contains three integers u,v,c , which means node u and node v are connected by an edge, it's cost is c(1c104).

You can assume that the sum of N will not exceed 106.
 
Output
For the i-th test case , first output Case #i: in a single line , then output N lines , for the i-th line , output ans[i] in a single line.
 
Sample Input
1 5 4 1 7 7 7 1 2 6 1 3 1 2 4 8 3 5 2
 
Sample Output
Case #1: 15 10 14 9 15
 

题解来自:http://www.cnblogs.com/tun117/p/5834536.html
题意:n个点组成的树,点和边都有权值,当第一次访问某个点的时候获得利益为点的权值
每次经过一条边,丢失利益为边的权值。问从第i个点出发,获得的利益最大是多少。
输入:
测试样例组数T
n
n个数每个点的权值
n-1条无向边 a b c a和b是点的标号,c是边的权值。
思路:
注意题目只强调是从某个点出发,并不一定要回到该点。
考虑树形DP。
先随便定义一个树根。然后对于某个点,我们需要维护它子树方向的两个值
1.从该点出发,最终要回到该点的利益的最大值
2.从该点出发,最终不必回到该点的利益的最大值,以及最后一次从该点出发的是哪个儿子节点。
3.从该点出发,最终不必回到该点的利益的第二大值,以及最后一次从该点出发的是哪个儿子节点。
先求出回到该点的利益的最大值,然后枚举它的儿子节点,作为最后出去的节点,即该节点不返回。
第二和第三个值把枚举所有儿子作为最后一次出发的情况然后排序记录下前两个就可以了。
以上是第一次DFS所做的工作。
然后对于每个点维护三个值,进行第二次DFS。
1.从该点出发所有方向(子树方向和父亲方向)回到该点的利益的最大值。
2.从该点出发所有方向,不必回到该点的利益的最大值,并保存最后一个出发的儿子节点的标号。
3.从该点出发所有方向,不必回到该点的利益的第二大值,并保存最后一个出发的儿子节点的标号。
第1个值的维护只需要将子树方向和减掉本身所在子树所影响的父亲方向的值加起来即可。
对于第二个和第三个值,我们可以将子树方向上最大的两个值加上父亲方向回来所带来的利益,与
父亲方向作为最后一次出发的点不回来的利益这三个值中求取两个最大的即可。
之所以要维护第二大的值,是因为当父亲节点最终的答案(即可以不回来)的最后一次访问的点恰
好是我们要求取的它的儿子节点的时候,我们可以用次大的值来确定当该儿子节点的父亲方向作为
最后一次访问的方向的时候的利益。
最后所有的ans[i][1]就是答案。
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define clr(x) memset(x,0,sizeof(x))
  6 #define clr_1(x) memset(x,-1,sizeof(x))
  7 #define LL long long
  8 #define mod 1000000007
  9 using namespace std;
 10 const int N=1e5+10;
 11 struct edg
 12 {
 13     int next,to;
 14     LL val;
 15 }edge[N*2];
 16 int head[N],ecnt;
 17 void addedge(int u,int v,LL val)
 18 {
 19     edge[++ecnt]=(edg){head[u],v,val};
 20     head[u]=ecnt;
 21     return ;
 22 }
 23 LL allans[N][2],ans[N][2],allf[N],f[N],cpt[5],ct[5];
 24 int dir[5],pt[N][2],allpt[N][2];
 25 int n,m,t,T,u,vv;
 26 LL v[N];
 27 LL p;
 28 bool cmp(int a,int b)
 29 {
 30     return ct[a]>ct[b];
 31 }
 32 void dfs1(int u,int pre)
 33 {
 34     f[u]=v[u];
 35     pt[u][0]=pt[u][1]=u;
 36     for(int i=head[u];i!=-1;i=edge[i].next)
 37     {
 38         if(edge[i].to!=pre)
 39         {
 40             dfs1(edge[i].to,u);
 41             f[u]=max(f[u],f[u]+f[edge[i].to]-2*edge[i].val);
 42         }
 43     }
 44     ans[u][0]=ans[u][1]=f[u];
 45     for(int i=head[u];i!=-1;i=edge[i].next)
 46         if(edge[i].to!=pre)
 47             if(f[edge[i].to]-2*edge[i].val<=0)
 48             {
 49                 if(ans[u][0]<f[u]+ans[edge[i].to][0]-edge[i].val)
 50                  {
 51                     ans[u][0]=f[u]+ans[edge[i].to][0]-edge[i].val;
 52                     pt[u][0]=edge[i].to;
 53                  }
 54             }
 55             else
 56             {
 57                 if(ans[u][0]<f[u]+ans[edge[i].to][0]-f[edge[i].to]+edge[i].val)
 58                  {
 59                     ans[u][0]=f[u]+ans[edge[i].to][0]-f[edge[i].to]+edge[i].val;
 60                     pt[u][0]=edge[i].to;
 61                  }
 62             }
 63     for(int i=head[u];i!=-1;i=edge[i].next)
 64         if(edge[i].to!=pre && edge[i].to!=pt[u][0])
 65             if(f[edge[i].to]-2*edge[i].val<=0)
 66             {
 67                 if(ans[u][1]<f[u]+ans[edge[i].to][0]-edge[i].val)
 68                  {
 69                     ans[u][1]=f[u]+ans[edge[i].to][0]-edge[i].val;
 70                     pt[u][1]=edge[i].to;
 71                  }
 72             }
 73             else
 74             {
 75                 if(ans[u][1]<f[u]+ans[edge[i].to][0]-f[edge[i].to]+edge[i].val)
 76                  {
 77                     ans[u][1]=f[u]+ans[edge[i].to][0]-f[edge[i].to]+edge[i].val;
 78                     pt[u][1]=edge[i].to;
 79                  }
 80             }
 81     return ;
 82 }
 83 void dfs2(int u,int pre,LL cost)
 84 {
 85     LL k=(f[u]-2*cost)>0?(allf[pre]-f[u]+2*cost):allf[pre];
 86     allf[u]=max(f[u],f[u]+k-2*cost);
 87     ct[0]=max(ans[u][0]+k-2*cost,ans[u][0]);
 88     cpt[0]=pt[u][0];
 89     ct[1]=max(ans[u][1]+k-2*cost,ans[u][1]);
 90     cpt[1]=pt[u][1];
 91     k=(f[u]-2*cost>0)?(f[u]-2*cost):0;
 92     ct[2]= f[u]+((allpt[pre][0]==u)?(allans[pre][1]-k):(allans[pre][0]-k))-cost;
 93     cpt[2]=pre;
 94     ct[3]=allf[u];
 95     cpt[3]=u;
 96     ct[4]=allf[u];
 97     cpt[4]=u;
 98     for(int i=0;i<5;i++)
 99         dir[i]=i;
100     sort(dir,dir+5,cmp);
101     for(int i=0;i<2;i++)
102     {
103         allans[u][i]=ct[dir[i]];
104         allpt[u][i]=cpt[dir[i]];
105     }
106     for(int i=head[u];i!=-1;i=edge[i].next)
107         if(edge[i].to!=pre)
108             dfs2(edge[i].to,u,edge[i].val);
109     return ;
110 }
111 int main()
112 {
113     scanf("%d",&T);
114     for(int kase=1;kase<=T;kase++)
115     {
116         scanf("%d",&n);
117         for(int i=1;i<=n;i++)
118         {
119             scanf("%lld",&v[i]);
120         }
121         for(int i=1;i<=n;i++)
122             head[i]=-1;
123         ecnt=0;
124         for(int i=2;i<=n;i++)
125         {
126             scanf("%d%d%lld",&u,&vv,&p);
127             addedge(u,vv,p);
128             addedge(vv,u,p);
129         }
130         dfs1(1,1);
131         allf[1]=f[1];
132         allans[1][0]=ans[1][0];
133         allpt[1][0]=pt[1][0];
134         allans[1][1]=ans[1][1];
135         allpt[1][1]=pt[1][1];
136         for(int i=head[1];i!=-1;i=edge[i].next)
137             dfs2(edge[i].to,1,edge[i].val);
138         printf("Case #%d:
",kase);
139         for(int i=1;i<=n;i++)
140             printf("%lld
",allans[i][0]);
141     }
142     return 0;
143 }
View Code
原文地址:https://www.cnblogs.com/wujiechao/p/7571737.html