CF1042F Leaf Sets
题意
给你一棵树,要求你把所有叶子分成一些集合
定义一个集合的代价为集合中距离最远点对的距离
给出 k ,求在最大集合代价不超过 k 的前提下,划分出的最少集合数
先尝试列一些式子和性质(看一些题解), 发现:
当 depest[sx_i]+ depest[sx_j] +2 <= k 时,子树中的集合才可以合并成为一个集合
这很显然,但不把它列出来我并不能意识到拿它作为更新的条件
似乎可以设 f[x] = Σf[sx_i] 表示当前节点子树中的集合数,然后根据上边的式子更新一下合并后的 f[x]
这是可做的然而有点麻烦,主要在于有一些已经无法合并的集合,这需要额外乱搞
可以这样做:
每次向上更新的时候,不将无法合并的集合向上更新,只留下还可能被更新的,
这样只需要在 dfs 时返回剩下的集合直接计入答案即可
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cctype>
#include<queue>
using namespace std;
const int MAXN = 1000005;
struct EDGE{
int nxt, to;
EDGE(int NXT = 0, int TO = 0) {nxt = NXT; to = TO;}
}edge[MAXN << 1];
int n, k, totedge, Root = 1, ans;
int head[MAXN], dpst[MAXN], deg[MAXN];
inline int rd() {
register int x = 0;
register char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) {
x = x * 10 + (c ^ 48);
c = getchar();
}
return x;
}
inline void add(int x, int y) {
edge[++totedge] = EDGE(head[x], y);
head[x] = totedge;
++deg[y];
return;
}
int dfs(int x, int frm) {
if(deg[x] == 1) return 0;
priority_queue<int> q;
for(int i = head[x]; i; i = edge[i].nxt) if(edge[i].to != frm) {
int y = edge[i].to;
q.push(dfs(y, x) + 1);
}
int lst = q.top(); q.pop();
while(q.size() >= 1) {
if(lst + q.top() <= k) return lst;
++ans;
lst = q.top();
q.pop();
}
return lst;
}
int main() {
n = rd(); k = rd();
register int xx, yy;
for(int i = 1; i < n; ++i) {
xx = rd(); yy = rd();
add(xx, yy); add(yy, xx);
}
for(int i = 1; i <= n; ++i) if(deg[i] != 1) {
Root = i;
break;
}
dfs(Root, 0);
printf("%d\n", ans + 1);
return 0;
}
禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载
,用户转载请注明出处:https://www.cnblogs.com/xcysblog/

浙公网安备 33010602011771号