Codeforces 348E 树的中心点的性质 / 树形DP / 点分治
题意及思路:http://ydc.blog.uoj.ac/blog/12
在求出树的直径的中心后,以它为根,对于除根以外的所有子树,求出子树中的最大深度,以及多个点的最大深度的lca,因为每个点的最长路径一定经过根,所以找到最大深度的子树,然后在这个点和最大深度的lca上树上差分一下就好了。注意,此处的中心是sum / 2处的那个点(sum是直径的长度)
代码:
#include <bits/stdc++.h>
#define pii pair<int, int>
using namespace std;
const int maxn = 100010;
int f[maxn];
int d[maxn];
vector<pii> G[maxn];
int mx[maxn], mx_pos[maxn], dye[maxn], sum[maxn];
int v[maxn];
int ans, ans_cnt, root, pos, n, m;
void add(int x, int y, int z) {
G[x].push_back(make_pair(y, z));
G[y].push_back(make_pair(x, z));
}
bool dfs(int x, int fa, int now) {
int flag = (v[x] == 1);
d[x] = now;
for (auto y : G[x]) {
if(y.first == fa) continue;
int tmp = dfs(y.first, x, now + y.second);
flag |= tmp;
f[y.first] = x;
}
if(flag && d[x] > ans) {
ans = d[x];
pos = x;
}
return flag;
}
void get_root() {
dfs(1, -1, 0);
memset(d, 0, sizeof(d));
ans = 0;
root = pos;
dfs(root, -1, 0);
int Sum = d[pos], tmp = pos;
while(d[tmp] > d[pos] / 2) {
tmp = f[tmp];
}
root = tmp;
}
void update(int pos, int ch, int val) {
if(mx[pos] < mx[ch] + val) {
mx[pos] = mx[ch] + val;
mx_pos[pos] = mx_pos[ch];
} else if(mx[pos] == mx[ch] + val) {
mx_pos[pos] = pos;
}
}
bool dfs1(int x, int fa, int color) {
dye[x] = color;
int flag = (v[x] == 1);
if(flag == 1) mx_pos[x] = x;
for (auto y : G[x]) {
if(y.first == fa) continue;
int tmp;
tmp = dfs1(y.first, x, color);
f[y.first] = x;
if(tmp) {
update(x, y.first, y.second);
}
flag |= tmp;
}
return flag;
}
void dfs2(int x, int fa) {
for (auto y : G[x]) {
if(y.first == fa) continue;
dfs2(y.first, x);
sum[x] += sum[y.first];
}
if(sum[x] > ans && v[x] == 0) {
ans = sum[x];
ans_cnt = 1;
} else if(sum[x] == ans && v[x] == 0) {
ans_cnt++;
}
}
vector<pii> res;
map<int, int> mp;
set<int> s;
int tot;
void solve() {
for (auto y : G[root]) {
int tmp = dfs1(y.first, root, ++tot);
if(tmp) {
res.push_back(make_pair(mx[y.first] + y.second, mx_pos[y.first]));
}
}
if(v[root] == 1) {
res.push_back(make_pair(0, root));
}
sort(res.begin(), res.end());
s.insert(dye[res[res.size() - 1].second]);
for (int i = res.size() - 1; i >= 1; i--) {
if(res[i].first == res[i - 1].first) {
s.insert(dye[res[i].second]);
s.insert(dye[res[i - 1].second]);
} else {
break;
}
}
for (int i = 0; i < res.size(); i++) {
mp[res[i].first]++;
}
for (int i = 1; i <= n; i++) {
if(v[i] == 1) {
if(s.count(dye[i]) && s.size() > 1) {
if(s.size() > 2) {
sum[i]++;
} else {
for (int j = res.size() - 1; j >= 0; j--) {
if(dye[i] != dye[res[j].second]) {
sum[i]++;
sum[res[j].second]++;
sum[root]--;
break;
}
}
}
} else {
if(s.size() > 1) {
sum[i]++;
continue;
}
if(dye[i] != dye[res[res.size() - 1].second]) {
sum[i]++;
sum[res[res.size() - 1].second]++;
sum[root]--;
}
else {
sum[i]++;
if(mp[res[res.size() - 2].first] == 1) {
sum[res[res.size() - 2].second]++;
sum[root]--;
}
}
}
}
}
ans = ans_cnt = 0;
dfs2(root, -1);
} int main() {
int x, y, z;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m ;i++) {
scanf("%d", &x);
v[x] = 1;
}
for (int i = 1; i < n; i++) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
}
get_root();
solve();
printf("%d %d\n", ans, ans_cnt);
}
树形DP做法:我们不用树的直径中心的性质,可以通过树形DP求出最长链。怎么DP呢?首先对于每个点,我们维护在这颗子树中的所有点中,到这个点的最远的和次远的距离,以及这些点的LCA, 个数这些信息。之后,我们再DP一遍。到一个点的最路径,只有两种情况,一种是在子树内,一种是在子树外。对于在子树外的情况,我们可以通过到这个点的父亲节点的最长路径和自己的最长路径/次长路径,来确定到这个点的最长路径,然后去更新子树。剩下的操作和直径中心的操作一样了。
马上期末考试了,太忙了,代码先咕了,有时间再补QAQ
点分治做法继续留坑QAQ
Codeforces 348E 树的中心点的性质 / 树形DP / 点分治的更多相关文章
- 洛谷 P2634 聪聪可可 —— 树形DP / 点分治
题目:https://www.luogu.org/problemnew/show/P2634 今天刚学了点分治,做例题: 好不容易A了,结果发现自己写的是树形DP...(也不用找重心)(比点分治快) ...
- Codeforces 1097G Vladislav and a Great Legend [树形DP,斯特林数]
洛谷 Codeforces 这题真是妙的很. 通过看题解,终于知道了\(\sum_n f(n)^k\)这种东西怎么算. update:经过思考,我对这题有了更深的理解,现将更新内容放在原题解下方. ...
- codeforces 161 D. Distance in Tree(树形dp)
题目链接:http://codeforces.com/problemset/problem/161/D 题意:给出一个树,问树上点到点的距离为k的一共有几个. 一道简单的树形dp,算是一个基础题. 设 ...
- [CQOI2009]叶子的染色【性质+树形Dp】
Online Judge:Bzoj1304,Luogu P3155 Label:无根树,树形Dp 题目描述 给定一棵\(N\)个节点的无根树,它一共有\(K\)个叶子节点.你可以选择一个度数大于1的节 ...
- Codeforces 835 F Roads in the Kingdom(树形dp)
F. Roads in the Kingdom(树形dp) 题意: 给一张n个点n条边的无向带权图 定义不便利度为所有点对最短距离中的最大值 求出删一条边之后,保证图还连通时不便利度的最小值 $n & ...
- 51Nod - 1405 树的距离之和(树形DP)
1405 树的距离之和 题意 给定一棵无根树,假设它有n个节点,节点编号从1到n,求任意两点之间的距离(最短路径)之和. 分析 树形DP. 首先我们让 \(1\) 为根.要开两个数组 \(up \ d ...
- 【BZOJ2286】消耗战(虚树,DFS序,树形DP)
题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. ...
- 【BZOJ3611】大工程(虚树,DFS序,树形DP)
题意:有一棵树,树有边权,有若干次询问,给出一些点,求: 1.这些点互相之间的距离之和 2.点对距离中的最大和最小值 n<=1000000 q<=50000并且保证所有k之和<=2* ...
- codeforces 816 E. Karen and Supermarket(树形dp)
题目链接:http://codeforces.com/contest/816/problem/E 题意:有n件商品,每件有价格ci,优惠券di,对于i>=2,使用di的条件为:xi的优惠券需要被 ...
随机推荐
- 【记录】vue构建项目npm install错误run `npm audit fix` to fix them, or `npm audit` for details
今天构建vue项目执行npm install初始化后报错 run `npm audit fix` to fix them, or `npm audit` for details 出现这问题控制台会有一 ...
- 三、bootstrap-treeview
一.bootstrap-treeview 修饰标签为徽章 参考 https://www.cnblogs.com/bin521/p/8403588.html
- Android面向切面编程(AOP)(转)
转自:https://www.jianshu.com/p/aa1112dbebc7 一.简述 1.AOP的概念 如果你用java做过后台开发,那么你一定知道AOP这个概念.如果不知道也无妨,套用百度百 ...
- 【Java程序】约瑟夫环
今天看视频教程无意间看到了一个数3减1的问题,百度之发现叫约瑟夫环问题,于是写了程序,问题大致描述如下: 一群带有编号的孩子手拉手围成一个圈报数,开始的孩子数1,他右边数2,再右边数3,数到n的孩子o ...
- Magolor的数据结构作业
\(CodeForces 706E ~Working routine\) 给出一个矩阵,每次操作交换两个子矩阵,求最后状态. 使用链表存储,每次交换后,影响到的之后矩阵边缘的指针,暴力修改. \(~~ ...
- 每天一个linux命令:mv(7)
mv mv命令可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. 在跨文件系统移动文件时,mv先拷贝,再将原有文件删除, ...
- hdu 2089 不要62 (数位dp)
Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别 ...
- 【Flutter学习】事件处理与通知之事件处理
一,概述 移动应用中一个必不可少的环节就是与用户的交互,在Flutter中提供的手势检测为GestureDetector. Flutter中的手势系统分为二层: 第一层是触摸原事件(指针) Point ...
- jdbc baseDAO 以及 每个类的继承
首先是baseDAO,用来作为DAO的父类 package dao; import java.lang.reflect.Field; import java.sql.Connection; impor ...
- HTML5: HTML5 Web Workers
ylbtech-HTML5: HTML5 Web Workers 1.返回顶部 1. HTML5 Web Workers web worker 是运行在后台的 JavaScript,不会影响页面的性能 ...