【codeforces 274B】【树形DP】 B. Zero Tree【一棵树,每个点有权值,每次操作可以对一个联通子集中的点全部加或者减1,且每次操作必须包含点1,问最少多少次操作权值全为0】
2016-10-05 14:26
881 查看
传送门:B. Zero Tree
描述:
B. Zero Tree
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
A tree is a graph with n vertices and exactly n - 1 edges;
this graph should meet the following condition: there exists exactly one shortest (by number of edges) path between any pair of its vertices.
A subtree of a tree T is a tree with both vertices and edges as subsets
of vertices and edges of T.
You're given a tree with n vertices. Consider its vertices numbered with integers from 1 to n.
Additionally an integer is written on every vertex of this tree. Initially the integer written on the i-th vertex is equal to vi.
In one move you can apply the following operation:
Select the subtree of the given tree that includes the vertex with number 1.
Increase (or decrease) by one all the integers which are written on the vertices of that subtree.
Calculate the minimum number of moves that is required to make all the integers written on the vertices of the given tree equal to zero.
Input
The first line of the input contains n (1 ≤ n ≤ 105).
Each of the next n - 1 lines contains two integers ai and bi (1 ≤ ai, bi ≤ n; ai ≠ bi)
indicating there's an edge between vertices ai and bi.
It's guaranteed that the input graph is a tree.
The last line of the input contains a list of n space-separated integers v1, v2, ..., vn (|vi| ≤ 109).
Output
Print the minimum number of operations needed to solve the task.
Please, do not write the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams
or the %I64dspecifier.
Examples
input
output
题意:
给出一棵树,每个点有权值,每次操作可以对一个联通子集中的点全部加1,或者全部减1,且每次操作必须包含点1,问最少通过多少次操作可以让整棵树每个点的权值变为0.
题目定义的subtree,不过这个subtree和子树的概念还是有些不同的
思路:
定义状态up[u],down[u]代表点u被加操作的次数和点u被减操作的次数因为必须包含点1,所以我们将树的根定在点1,那么对于每一点的子树中点,如果要修改的话,那么一定会经过当前这个点,因为这是通向根的必经之路,所以把1设为根。所以对于每个点u,它被加修改和减修改的次数,就是它的儿子中进行该操作的最大次数,因为如果有两个儿子都需要进行该操作,那么完全可以两步并一步,所以只需要取最大值就可以了。那么也就是
up[u]=maxv adjacent to uup[v]
down[u]同理。因为每次修改一定会修改点1,所以最后答案就是up[1]+down[1]
代码:
#include <bits/stdc++.h>
#define pr(x) cout << #x << "= " << x << " " ;
#define pl(x) cout << #x << "= " << x << endl;
#define ll __int64
using namespace std;
template<class T> void read(T&num) {
char CH; bool F=false;
for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
if(!p) { puts("0"); return; }
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
}
const int N=1e5+10;
ll val
,down
,up
;
std::vector<int> e
;
int n;
void dfs(int u,int fa){
up[u]=down[u]=0;
for(int i=0; i<e[u].size(); i++){
int v=e[u][i];
if(v==fa)continue;
dfs(v, u);
up[u]=max(up[u], up[v]);
down[u]=max(down[u], down[v]);
}
val[u]+=up[u]-down[u];
if(val[u]>0)down[u]+=val[u];
else up[u]-=val[u];
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
read(n);
for(int i=1; i<n; i++){
int x,y;
read(x);read(y);
e[x].push_back(y);
e[y].push_back(x);
}
for(int i=1; i<=n; i++)read(val[i]);
dfs(1, 0);
print(up[1]+down[1]);
return 0;
}
/*input
5
2 3
4 5
2 5
1 3
0 2 1 4 3
output
8*/
描述:
B. Zero Tree
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
A tree is a graph with n vertices and exactly n - 1 edges;
this graph should meet the following condition: there exists exactly one shortest (by number of edges) path between any pair of its vertices.
A subtree of a tree T is a tree with both vertices and edges as subsets
of vertices and edges of T.
You're given a tree with n vertices. Consider its vertices numbered with integers from 1 to n.
Additionally an integer is written on every vertex of this tree. Initially the integer written on the i-th vertex is equal to vi.
In one move you can apply the following operation:
Select the subtree of the given tree that includes the vertex with number 1.
Increase (or decrease) by one all the integers which are written on the vertices of that subtree.
Calculate the minimum number of moves that is required to make all the integers written on the vertices of the given tree equal to zero.
Input
The first line of the input contains n (1 ≤ n ≤ 105).
Each of the next n - 1 lines contains two integers ai and bi (1 ≤ ai, bi ≤ n; ai ≠ bi)
indicating there's an edge between vertices ai and bi.
It's guaranteed that the input graph is a tree.
The last line of the input contains a list of n space-separated integers v1, v2, ..., vn (|vi| ≤ 109).
Output
Print the minimum number of operations needed to solve the task.
Please, do not write the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams
or the %I64dspecifier.
Examples
input
3 1 2 1 3 1 -1 1
output
3
题意:
给出一棵树,每个点有权值,每次操作可以对一个联通子集中的点全部加1,或者全部减1,且每次操作必须包含点1,问最少通过多少次操作可以让整棵树每个点的权值变为0.
题目定义的subtree,不过这个subtree和子树的概念还是有些不同的
思路:
定义状态up[u],down[u]代表点u被加操作的次数和点u被减操作的次数因为必须包含点1,所以我们将树的根定在点1,那么对于每一点的子树中点,如果要修改的话,那么一定会经过当前这个点,因为这是通向根的必经之路,所以把1设为根。所以对于每个点u,它被加修改和减修改的次数,就是它的儿子中进行该操作的最大次数,因为如果有两个儿子都需要进行该操作,那么完全可以两步并一步,所以只需要取最大值就可以了。那么也就是
up[u]=maxv adjacent to uup[v]
down[u]同理。因为每次修改一定会修改点1,所以最后答案就是up[1]+down[1]
代码:
#include <bits/stdc++.h>
#define pr(x) cout << #x << "= " << x << " " ;
#define pl(x) cout << #x << "= " << x << endl;
#define ll __int64
using namespace std;
template<class T> void read(T&num) {
char CH; bool F=false;
for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
if(!p) { puts("0"); return; }
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
}
const int N=1e5+10;
ll val
,down
,up
;
std::vector<int> e
;
int n;
void dfs(int u,int fa){
up[u]=down[u]=0;
for(int i=0; i<e[u].size(); i++){
int v=e[u][i];
if(v==fa)continue;
dfs(v, u);
up[u]=max(up[u], up[v]);
down[u]=max(down[u], down[v]);
}
val[u]+=up[u]-down[u];
if(val[u]>0)down[u]+=val[u];
else up[u]-=val[u];
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
read(n);
for(int i=1; i<n; i++){
int x,y;
read(x);read(y);
e[x].push_back(y);
e[y].push_back(x);
}
for(int i=1; i<=n; i++)read(val[i]);
dfs(1, 0);
print(up[1]+down[1]);
return 0;
}
/*input
5
2 3
4 5
2 5
1 3
0 2 1 4 3
output
8*/
相关文章推荐
- 【codeforces 691 D】【并查集 或者 dfs】aps in Permutation【给一个1到N的排列,M个操作,每次可以交换X Y位置上的数字,求可以得到的最大字典序的数列】
- 【codeforces 731D】【差分+线段扫描 思维题】80-th Level Archeology【给你n个word,现在要使得word按字典序排列,随便操作多少次,每次可以使每个word+1】
- 度度熊有一张网格纸,但是纸上有一些点过的点,每个点都在网格点上,若把网格看成一个坐标轴平行于网格线的坐标系的话,每个点可以用一对整数x,y来表示。度度熊必须沿着网格线画一个正方形,使所有点在正方形的内部或者边界。然后把这个正方形剪下来。问剪掉正方形的最小面积是多少。
- n从1开始,每个操作可以选择对n加1或者对n加倍,想获取的2016,最少需要多少个操作。
- hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。
- 【codeforces 519 D】【hash+dp】【给出一个字符串,给出每个字母的权值,求字符串的子串中首尾相等,除去首尾字母的权值和为0的数量。】
- Hdu 5812 Distance(三种操作. 1.插入x 2.删除x 3.在集合中找到一个数y,使得y->x,每次能除以一个素数或者乘上一个素数,问最少的操作次数)
- codeforces 274B B. Zero Tree(树形dp)
- 【atcoder 10】【博弈论+树形dp】【对一棵树每次从棋子所在节点移走一个石头,将棋子移到与当前节点相邻的节点】
- 笔试面试题:25匹赛马,5个跑道,每次有5匹马可以同时比赛。问最少比赛多少次可以知道跑得最快的5匹马
- 【c语言】为下面的函数原型编写函数定义,这个字符串参数必须包含一个或者多个数字,函数应该把这些数字字符转换为整数并返回这个整数。
- 字符串参数必须包含一个或者多个数字,函数应该把这些数字字符转换为整数并返回这个整数。如果字符串参数包含了任何非数字字符,函数就返回零
- uva 11584 题目大意: 给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串。问最少可以分割成多少个。
- int ascii_to_integer(char *str); 这个字符串参数必须包含一个或者多个数字,函数应该把这些数字字符转换为整数并返回这个整数。
- 每日总结:每个 GROUP BY 表达式必须至少包含一个不是外部引用的列、加载页面时调用Js方法、调用Js文件中的方法
- 练习1-21 编写程序entab,将空格串替换成最少数量的制表符和空格,但要保持单词之间的间隔不变。假设制表符终止位的位置与练习1-20的detab程序的情况相同。当使用一个制表符或者一个空格都可以到达下一个制表符终止位时,选用哪种替换字符比较好。
- 写一个字符串函数,这个字符串参数必须包含一个或者多个数字,函数应该把这些数字字符转换为整数并返回这个整数。
- 本来从动态壁纸预览页面设置一个动态壁纸回到桌面便可以看到桌面动态壁纸,可以观察得到自己的动态壁纸是否设置成功了(必须知道设置是否成功的结构,因为还有一些操作需要完成)! 但是现在是要在自己的应用中进入
- 【C语言】为下面的函数原型编写函数定义: int ascii_to_integer(char *str); 这个字符串参数必须包含一个或者多个数字,函数应该把这些数字字符转换为整数并返回这个整数。
- 阿里巴巴面试算法题目:25匹赛马,5个跑道,也就是说每次有5匹马可以同时比赛。问最少比赛多少次可以知道跑得最快的5匹马