题目链接


题目大意:
给你一棵树,问你对于每一个点是否可以在树上删掉一条边,再增加一条边,使它成为树的重心。
tips:一个点成为重心的条件为它的每个子树大小不超过n/2。


解题思路:首先树上问题一般都要转有根树
1.对于一个点它有两个方向:就是向它儿子,就是向它父亲
2.要实现树形dp我们要找到儿子和父亲的关系
3.首先我们发现如果一个节点要是边连出去的子树最多只有一个大于n/2n/2n/2
4.如果这个子树的大于n/2n/2n/2那么我们就要对这个子树进行操作
5.首先我们要从子树挑除一个最大的并且不超过n/2n/2n/2的子树[子树的子树]直接连接到目标点,并且剩下的不能超过n/2n/2n/2


通过上面的分析:我们知道我们对于每颗子树要求什么?:
1.首先我们要求出每个子树的大小判断是否大于n/2n/2n/2
2.我们要统计子树里面小于n/2的最大的子树是多大
3.设一个down[u]是u节点向下子树中的最大值,up[u]是向上的最大值,在第二次扫描的时候如果父亲方向的siz<n/2的话我们就要更新up[u]
4.其实这里我们可以用一个set去维护每次取最大值


代码:


#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <limits.h>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define hash Hash
#define next Next
#define pb push_back
#define f first
#define s second
#define y1 Y
using namespace std;
const int N = 1e7 + 10, MOD = 1e9 + 7;
const int maxn = 4e5 + 10;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{read(first);read(args...);
}
vector<int>G[maxn << 1];
int n;
int maxsiz[maxn << 1];//统计最大的子树在筛选的时候要去除大于n/2的子树
int siz[maxn << 1];//统计siz
int down[maxn << 1], up[maxn << 1];
inline void dfs(int u, int fa)
{siz[u] = 1; for(int i = 0; i < G[u].size(); ++ i){int v = G[u][i];if(v == fa) continue;dfs(v,u);siz[u] += siz[v];down[u] = max(down[u],(siz[v]>n/2)?down[v]:siz[v]);maxsiz[u] = max(siz[v],maxsiz[u]);}return;
}inline void dfs1(int u, int fa)
{multiset<int> s;for(auto it : G[u])if(it != fa)s.insert((siz[it]>n/2)?down[it]:siz[it]);for(auto it :G[u]){if(it == fa) continue;if(n-siz[it]<=n/2) up[it] = max(up[it],n-siz[it]);else {up[it] = max(up[it],up[u]);s.erase(s.find((siz[it]>n/2)?down[it]:siz[it]));if(!s.empty()) up[it] = max(up[it],*s.rbegin());s.insert((siz[it]>n/2)?down[it]:siz[it]);}dfs1(it,u);}
}int main()
{read(n);for(int i = 1; i < n; ++ i){int l, r;read(l,r);G[l].pb(r);G[r].pb(l);}dfs(1,0);dfs1(1,0);for(int i = 1; i <=n; ++i){int ans = 1;if(maxsiz[i] > n / 2) ans = maxsiz[i] - down[i] <= n / 2;if(n - siz[i] > n / 2) ans = n - siz[i] - up[i] <= n / 2;cout << ans <<" ";}return 0;
}

codeforce708C:树形dp+二次扫描相关推荐

  1. nssl1163-小x游世界树【树形dp,二次扫描和换根法】

    正题 题目大意 一棵树,一条边的权是原本的权值减去出发点的加速. 求一个点使得这个点到所有点路径边权和最小. 解题思路 我们先求出以1为根时的答案 然后用换根法 我们从1转移到2,我们会发现 红色的部 ...

  2. POJ3585-Accumulation Degree【树形dp,二次扫描与换根法】

    正题 题目链接:http://poj.org/problem?id=3585 题目大意 有棵无根树,当你选择一个点为根时,价值就是根节点到所有叶节点的路上的最小权值之和. 解题思路 我们可以先计算一次 ...

  3. HDU2196[树形dp+二次扫描]java和c++版本题解

    题目大意:就是给你一颗树,问你从每个点出发能到达的最远距离是多少,第一行输入点的个数nnn,第n−1n-1n−1行是输入两个数x,yx,yx,y,一个是第iii行是第iii个点连接上xxx,距离是yy ...

  4. Educational Codeforces Round 67 (Rated for Div. 2)(D思维题 线段树/E树形dp(换根dp) 二次扫描与换根法)

    心得 D写了个假算法被hack了wtcl- E据涛神说是二次扫描与换根法,看了看好像和树形dp差不多 F概率dp G费用流 回头再补 思路来源 马老师 归神 贤神等代码 http://www.mami ...

  5. 最大疯子树-树形dp+换根+二次扫描

    分析: 疯子树肯定还是一棵树. 所以,所谓的最短路径就是吓唬你的,树上两点之间有且只有一条路径. b1和b2必须是相邻的,否则不可能是一棵疯子树. 再想一想,用同样的方式构造剩下的点的话,那么可以得到 ...

  6. 最大疯子树:树形DP优化:二次扫描+换根法(poj3585)

    相信看这篇文的人应该是会一些简单的线性树形dp的吧-- 如果有不会的请先看看树形dp基础吧--比如这道题没有上司的舞会 其实之所以想写这篇文是因为前段时间被教练骗去叫去参加一场UESTC组织主办的线下 ...

  7. 最大搜索二叉子树大小(树形dp)

    给定一颗二叉树的头节点head,返回这棵二叉树中最大的二叉搜索子树 (二叉搜索树:该二叉树中左子树所有节点比它小,右子树所有节点比它大 ): 思路: 这是一道分析可能性求解在二叉树上做类似动态规划的问 ...

  8. leetcode 235. 二叉搜索树的最近公共祖先(Java版,树形dp套路)

    题目 原题地址:leetcode 235. 二叉搜索树的最近公共祖先 说明: 所有节点的值都是唯一的. p.q 为不同节点且均存在于给定的二叉搜索树中. 题解 关于 树形dp 套路,可以参考我的另一篇 ...

  9. AcWing1074. 二叉苹果树(树形DP)题解

    题目传送门 题目描述 有一棵二叉苹果树,如果树枝有分叉,一定是分两叉,即没有只有一个儿子的节点. 这棵树共 N 个节点,编号为 1 至 N,树根编号一定为 1. 我们用一根树枝两端连接的节点编号描述一 ...

最新文章

  1. Consul 服务注册与发现03—— 服务消费者
  2. 使用Nomad构建弹性基础架构: 作业生命周期
  3. 全端开发——html简介与常用标签
  4. Angular Universal 官网翻译
  5. barrier相關知識點整理(还没搞完)
  6. 计算机风扇维修,教你简单修理电脑散热风扇
  7. 保证你现在和未来不失业的十种关键技术
  8. 二维码扫描和应用跳转
  9. 程序猿爆笑选集(1)
  10. C语言学习笔记---结构体指针
  11. mysql hibernate id generator,hibernate annoation (三 id生成器)
  12. sublime设置代码缩进
  13. perl语言hello world程序
  14. linux安装五笔输入法centos,CentOS 7系统怎么安装极点五笔输入法?
  15. Win10系统设置开机默认开启数字小键盘
  16. css flex实现经典的三栏布局
  17. 学校快递代领PHP源码_PHP校园帮忙领取快递平台
  18. 复旦大学与国网上海共建“电力大数据实验室”
  19. 300最不常用的springboot计算机毕业设计题目汇总,总有你需要用到的
  20. Abp vnext Web应用程序开发教程 2 —— 图书列表页面

热门文章

  1. idea软件,如何不每次弹出“欢迎界面!”
  2. 技巧 | OpenCV中如何绘制与填充多边形
  3. 深度学习的实时面部姿势估计研究
  4. 从词向量到Bert——简单作业题+讲解
  5. Nginx 安装及配置
  6. 报错——StackOverflowError
  7. Android Studio中新建和引用assets文件
  8. Fastjson 序列化,反序列化Map对象排序问题(字符串转map,map转字符串)
  9. QPushButton 响应回车 设置默认按钮
  10. SqlServer按照指定顺序对字段进行排序