类直径树上贪心

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;
}
相关推荐
A懿轩A2 天前
C/C++ 数据结构与算法【树和二叉树】 树和二叉树,二叉树先中后序遍历详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·二叉树·
Tisfy3 天前
LeetCode 1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解
算法·leetcode·优先队列·贪心·
硕风和炜12 天前
【LeetCode: 1338. 数组大小减半 + 哈希表 + 贪心】
算法·leetcode·散列表·贪心·哈希表
硕风和炜21 天前
【LeetCode: 316. 去除重复字母 + 栈 + 哈希表】
java·算法·leetcode·散列表·贪心··哈希表
我是哈哈hh25 天前
专题二十四_贪心策略(2)_算法专题详细总结
数据结构·c++·算法·leetcode·贪心算法·贪心
sweetheart7-725 天前
LeetCode763. 划分字母区间(2024冬季每日一题 23)
算法·力扣·贪心
不修×蝙蝠25 天前
数据结构--二叉树删除树节点
数据结构·二叉树··删除·删除节点
闻缺陷则喜何志丹1 个月前
【C++贪心 数论】991. 坏了的计算器|1909
c++·算法·力扣·数论·贪心·计算器·最小
一直学习永不止步1 个月前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
_whitepure1 个月前
常用数据结构详解
java·链表····队列·稀疏数组