Codeforces 348E 树的中心点的性质 / 树形DP / 点分治

Posted pkgunboat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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先留个坑。。。。

以上是关于Codeforces 348E 树的中心点的性质 / 树形DP / 点分治的主要内容,如果未能解决你的问题,请参考以下文章

D. Lost Tree树的二分图性质——Codeforces LATOKEN Round 1 (Div. 1 + Div. 2)

D. Lost Tree树的二分图性质——Codeforces LATOKEN Round 1 (Div. 1 + Div. 2)

Codeforces 1005F Berland and the Shortest Paths 最短路树性质

Codeforces 1108F MST Unification(最小生成树性质)

Codeforces 686 D - Kay and Snowflake

Codeforces Round #566 (Div. 2)