CF1119F Niyaz and Small Degrees
这种要求所有点都满足一个性质的东西,我们可以用树形\(dp\)做。
先考虑一个暴力的\(dp\)怎么做呢。
设\(f[u][1/0]\)为\(u\)点满足性质的,和父节点的边删不删的最小值。
那么有\(f[u][0] = \sum{min(f[v][1] + w,f[v][0])}\)
同理也有\(f[u][1]\)
那么考虑先设\(f[u][0] = \sum f[v][0]\)
往一个堆里丢入\(f[v][1] + w - f[v][0]\)取最前面的负数点,以及一些为了满足答案的正数点的和加入\(f[u][0]\)即可
\(f[u][1]\)则同理。
CF1119F Niyaz and Small Degrees
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
#define N 250005
struct P{int to,next,v;}e[N << 1];
ll n;
int cnt,head[N];
inline void add(int x,int y,int v){
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].v = v;
head[x] = cnt;
}
ll X;
ll f[N][2];
inline void dfs(int u,int fa){
std::vector<long long>val;
f[u][0] = f[u][1] = 0;
for(int i = head[u];i;i = e[i].next){
int v = e[i].to;
if(v == fa)
continue;
dfs(v,u);
val.push_back(f[v][1] + e[i].v - f[v][0]);
f[u][0] += f[v][0];
}
f[u][1] = f[u][0];
std::sort(val.begin(),val.end());
int s = val.size();
for(int i = 0;i < s && (i <= s - X - 1|| val[i] < 0);++i)
f[u][1] += val[i];
if(!X){f[u][0] = 0x3f3f3f3f3f;return;}
++s;
for(int i = 0;i < s - 1 && (i <= s - X - 1 || val[i] < 0);++i)
f[u][0] += val[i];
}
int main(){
scanf("%lld",&n);
for(int i = 1;i <= n - 1;++i){
int x,y,v;
scanf("%d%d%d",&x,&y,&v);
add(x,y,v);
add(y,x,v);
}
for(X = 0;X < n;++X)
dfs(1,0),std::cout<<f[1][1]<<" ";
}
复杂度\(O(n^2log)\)
考虑怎么优化这个复杂度,我们发现有些点如果度数小于当前有的度数,那么他的\(f[u][1],f[u][0]\)都是\(0\),那么相当于只往和他相邻的点的堆里加入\(w\),那么对每个点都维护一颗平衡树,然后算答案就好了,为了保证复杂度,还要对边按出点的点的度数排序。