Loading

CF1385F Removing Leaves 题解

看到题,感觉像树形DP,遂设计DP式子。

\(dp_u\) 表示以 \(u\) 为根的子树内最多能删多少次(不删 \(u\))。

那么每次子节点到父节点增加的贡献就是 \(\lfloor\frac{子树大小为1的子节点个数}{k}\rfloor\)

得出式子 \(dp_u = \sum_{v\in son_u} dp_v + (\sum_{v\in son_u} [dp_v \times k=siz_v]) \div k\)

为方便,我们把 \(\sum_{v\in son_u} [dp_v \times k=siz_v]\)\(sum_u\) 表示。

这是一颗无根树,所以我们进行换根。

设从 \(u\) 换到 \(v\) ,变量 \(x\) 换根前为 \(x_0\) 换根后为 \(x\)

\(dp_u=dp_{u0}-dp_{v0}-sum_{u0}\div k+(sum_{u0} - [dp_{v0} \times k = siz_{v0} - 1]) \div k\)

\(siz_u=n-siz_{v0}\)

\(siz_v=n\)

\(dp_v = dp_{v0} + dp_u - sum_{v0} \div k + (sum_{v0} + [dp_u \times k = siz_u - 1]) \div k\)

\(sum_v=sum_{v0}+[dp_u\times k = siz_u - 1]\)

虽然这些式子看起来很复杂,但是是因为我写的屎。

这样我们就得到了一个 \(O(n)\) 的解法,虽然 \(1e5\) 没必要。

点击查看代码
#include <bits/stdc++.h>

using namespace std;

#define fi first
#define se second

typedef unsigned long long ull;
typedef long long ll;
using Pii = pair<int , int>;
using Pll = pair<ll , ll>;

const int N = 2e5 + 5;
constexpr int INF = 0x3F3F3F3F;
constexpr ll INFl = 0x3F3F3F3F3F3F3F3F;
constexpr int P = 1e9 + 7;

#define typ int
#define writesp(x) write(x) , putchar(32)
#define writeln(x) write(x) , putchar(10)
inline char gc(){static char buf[100000] , *p1 = buf , *p2 = buf;return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;}
#define getc gc
inline typ read(){typ x = 0; bool f = 0;char ch = getc();while(!isdigit(ch)){f |= (ch == '-');ch = getc();}while(isdigit(ch)){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getc();}return (f ? -x : x);}
inline void write(typ x){if(x < 0) putchar('-') , x = -x;if(x / 10) write(x / 10);putchar(x % 10 ^ 48);}

int n , k;
struct edge {
	int to , nxt;
}e[N << 1];
int head[N] , cnt = 1;
void adde(int u , int v){
	e[ ++ cnt] = {v , head[u]};
	head[u] = cnt;
	e[ ++ cnt] = {u , head[v]};
	head[v] = cnt;
}
void clr(){
	cnt = 1;
	memset(head , 0 , sizeof head);
}

int dp[N] , siz[N] , sum[N];
void Dp(int u , int fa){
	siz[u] = 1;
	for(int i = head[u]; i; i = e[i].nxt){
		int v = e[i].to;
		if(v == fa) continue;
		Dp(v , u);
		siz[u] += siz[v];
		dp[u] += dp[v];
		sum[u] += (dp[v] * k == siz[v] - 1);
	}
	dp[u] += sum[u] / k;
}
int ans = 0;
void ch_rt(int u , int fa){
	ans = max(ans , dp[u]);
	for(int i = head[u]; i; i = e[i].nxt){
		int v = e[i].to;
		if(v == fa) continue;
		
		int dpu = dp[u] - dp[v] - sum[u] / k + (sum[u] - (dp[v] * k == siz[v] - 1)) / k;
		int sizu = siz[u] - siz[v];
		
		siz[v] = n;
		dp[v] = dp[v] + dpu - sum[v] / k + (sum[v] + (dpu * k == sizu - 1)) / k;
		sum[v] += (dpu * k == sizu - 1);
		
		ch_rt(v , u);
	}
}

void solve(){
	/*INIT*/
	clr();
	memset(dp , 0 , sizeof dp);
//	memset(siz , 0 , sizeof siz);
	memset(sum , 0 , sizeof sum);
	ans = 0;
	n = read() , k = read();
	for(int i = 1; i < n; ++ i){
		int u = read() , v = read();
		adde(u , v);
	}
	
	Dp(1 , 0);
	
	ch_rt(1 , 0);
	
	writeln(ans);
}

signed main(){
	int T = read();
	while(T -- ) solve();
	
	return 0;
}
posted @ 2024-05-10 15:14  TongKa  阅读(54)  评论(0)    收藏  举报