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\),那么对每个点都维护一颗平衡树,然后算答案就好了,为了保证复杂度,还要对边按出点的点的度数排序。

posted @ 2021-05-24 20:37  fhq_treap  阅读(42)  评论(0编辑  收藏  举报