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

  • 相关阅读:
    nginx原理及常用配置
    课程作业03-1
    Java动手动脑02
    Java课程作业02
    java课堂测试2
    Java验证码程序
    课程作业02-2
    课程作业02-1
    课程作业01
    《大道至简》第一章伪代码
  • 原文地址:https://www.cnblogs.com/dixiao/p/14806087.html
Copyright © 2020-2023  润新知