zoukankan      html  css  js  c++  java
  • 【题解】CF1324F

    Question

    题目大意:每个点不是黑点就是白点,求以每一个点为根时,选择出一个联通块,使得白点数与黑点数之差最大(白减黑)。

    (Solution)

    考虑先跑一遍(dp).

    可以写出一个比较显然的方程:(dp_i=val_i+sum_{jin son[i]}max(0,dp_j),val_i)是节点(i)的颜色,如果是白则为(1),否则为(-1).

    如果这样难不成要跑(n)遍?

    恭喜喜提( ext{Time Limit Error}).

    考虑只跑一遍,用第一遍的答案更新其它根的答案。

    考虑一个点(i),若已经知道(fa_i)的答案,怎么推出它的答案?

    考虑去掉它对(fa_i)的影响,在加上它本身的答案。

    值得注意的是,当它爹的答案本身就小于0时,就不用选了。

    所以,状态转移方程为(第二遍是(f,)第一遍是(dp.)):

    [f_i=max(0,f_{fa_i}-max(dp_i,0))+dp_i ]

    以上,这题(O(n))做完了。

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=2e5+10;
    int n,v[MAXN],head[MAXN<<1];
    int tot,cnt1[MAXN],vis[MAXN];
    int cnt2[MAXN],dp[MAXN],d[MAXN];
    struct edge{
    	int nxt,to;
    }e[MAXN<<1];
    inline void add(int x,int y){
    	e[++tot].to=y;
    	e[tot].nxt=head[x];
    	head[x]=tot;
    }
    void dfs(int x){
    	vis[x]=1;
    	if(v[x])cnt1[x]=1,d[x]=1;
    	else cnt2[x]=1,d[x]=-1;
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		if(!vis[j]){
    			dfs(j);
    			cnt1[x]+=cnt1[j];
    			cnt2[x]+=cnt2[j];
    			if(d[j]<=0)continue;
    			else d[x]+=d[j];
    		}
    	}
    }
    void solve(int x,int fa){
    	if(x!=1)dp[x]=max(0,dp[fa]-max(0,d[x]))+d[x];
    	for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa)solve(e[i].to,x);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)scanf("%d",&v[i]);
    	for(int i=1,x,y;i<n;++i){
    		scanf("%d%d",&x,&y);
    		add(x,y);add(y,x);
    	}
    	dfs(1);
    	dp[1]=d[1];
    	for(int i=1;i<=n;++i)vis[i]=0;
    	solve(1,0);
    	for(int i=1;i<=n;++i)printf("%d ",dp[i]);
    	cout<<endl;
    	return 0;
    } 
    
  • 相关阅读:
    记laravel项目,本地环境PHP7.1,线上PHP版本7.2,报错each函数废弃问题
    [教程] 《Mysql 实战 45 讲》
    PHP递归求和计算1加到n的和
    SSL原理
    PHP之抽象类与接口
    iOS调试之挂起线程
    iOS之Starfield
    iOS之透视效果
    CSS之框模型
    HTTP之CacheControl
  • 原文地址:https://www.cnblogs.com/h-lka/p/12592870.html
Copyright © 2011-2022 走看看