类直径树上贪心

http://cplusoj.com/d/senior/p/SS231109C

场上想到枚举点,然后最大值为高,然后可以求最大值。但是感觉计数会重


计数其实不会重,如图中,红色线段显然比蓝色线段优

所以我们枚举3叉点时没错的

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
 #define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
 #define debug(...) void(0)
#endif
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//srand(time(0));
#define N 500010
//#define M
//#define mo
struct node {
	int mx, cnt; 
	void init() { mx=-1e15; cnt=0; }
	node operator +(const node &A) const {
		if(A.mx>mx) return A; 
		if(mx>A.mx) return (*this); 
		return {mx, cnt+A.cnt}; 
	}
	node add() { node A=(*this); A.mx++; return A; }
}ans, f[N]; 
void operator += (node &A, node B) { A=A+B; }
int n, m, i, j, k, T;
int u, v, c[N]; 
vector<int>G[N]; 

void dfs1(int x, int fa) {
	f[x]={0, 1}; 
	for(int y : G[x]) if(y!=fa) {
		dfs1(y, x); f[x]+=f[y].add(); 
	}
	debug("> %lld : %lld %lld\n", x, f[x].mx, f[x].cnt); 
}

void dfs2(int x, int fa, node p) {
	debug("Shang %lld : %lld %lld\n", x, p.mx, p.cnt); 
	int z=G[x].size(), i, j, k=0; 
	vector<node>pre, lst, cao; 
	node dp[3][2], ndp[3][2];
	vector<int>ve; 
	pre.resize(z+2); lst.resize(z+2); ve.resize(z+2); 
	for(auto &t : pre) t.init(); 
	for(auto &t : lst) t.init(); 
	for(auto y : G[x]) if(y!=fa) ve[++k]=y; 
	pre[0]=p; 
	for(i=1; i<=k; ++i) pre[i]=pre[i-1]+f[ve[i]].add(); 
	for(i=k; i>=1; --i) lst[i]=lst[i+1]+f[ve[i]].add(); 
	for(i=1; i<=k; ++i) dfs2(ve[i], x, (pre[i-1]+lst[i+1]).add()); 
	
	if(c[x]<3) return ; 
	int mx=pre[k].mx; 
	debug("[%lld] %lld\n", k, mx); 
	for(i=1; i<=k; ++i) cao.pb(f[ve[i]].add()); cao.pb(p); 
	for(i=0; i<=2; ++i) for(j=0; j<=1; ++j) dp[i][j].init(); 
	dp[0][0]={0, 1}; 
	for(auto t : cao) {
		debug("# %lld %lld\n", t.mx, t.cnt); 
		for(i=0; i<=2; ++i) for(j=0; j<=1; ++j) ndp[i][j].init(); 
		for(i=0; i<=2; ++i) for(j=0; j<=1; ++j) {
			ndp[i][j|(t.mx==mx)]+=dp[i][j]; 
			if(i<2) {
				node cur = {dp[i][j].mx+mx*t.mx, dp[i][j].cnt*t.cnt}; 
				debug("** %lld(%lld %lld) %lld | %lld\n", cur.mx, dp[i][j].mx, mx*t.mx, cur.cnt, j); 
				ndp[i+1][j]+=cur; 
			}
		}
		for(i=0; i<=2; ++i) for(j=0; j<=1; ++j) dp[i][j]=ndp[i][j]; 
	}
	debug("=# %lld %lld\n", dp[2][1].mx, dp[2][1].cnt); 
	ans+=dp[2][1]; 
}

signed main()
{
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);
	#ifdef LOCAL
	  freopen("in.txt", "r", stdin);
	  freopen("out.txt", "w", stdout);
	#endif
//	T=read();
//	while(T--) {
//
//	}	
	n=read(); 
	for(i=1; i<n; ++i) {
		u=read(); v=read(); 
		G[u].pb(v); G[v].pb(u); ++c[u]; ++c[v]; 
		k=max(k, c[u]); k=max(k, c[v]); 
	}
	if(k<=2) return printf("0 1"), 0; 
	node p; p.init(); 
	dfs1(1, 0); 
	dfs2(1, 0, {0, 1}); 
	printf("%lld %lld\n", ans.mx, ans.cnt); 
	return 0;
}
相关推荐
一直学习永不止步19 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
_whitepure20 小时前
常用数据结构详解
java·链表····队列·稀疏数组
Tisfy3 天前
LeetCode 3244.新增道路查询后的最短距离 II:贪心(跃迁合并)-9行py(O(n))
算法·leetcode·题解·贪心·思维
一直学习永不止步23 天前
LeetCode题练习与总结:扁平化嵌套列表迭代器--341
java·leetcode·迭代器···队列·深度优先搜索
数据结构和算法1 个月前
数据结构——笛卡尔树详解
数据结构··二叉搜索树··笛卡尔树
IT规划师1 个月前
数据结构 - 树,三探之代码实现
数据结构·
韶瑜不会写代码1 个月前
7-1 玩转二叉树
c语言·数据结构·算法·
一直学习永不止步1 个月前
LeetCode题练习与总结:拼接最大数--321
java·leetcode·贪心·数组··双指针·单调栈
Tisfy1 个月前
LeetCode 0910.最小差值 II:贪心(排序)-小数大数分界线枚举(思考过程详解)
算法·leetcode·题解·贪心·枚举·思维·排序
CXDNW1 个月前
【算法篇】贪心类(1)(笔记)
c++·笔记·算法·leetcode·贪心