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;
    } 
    
  • 相关阅读:
    Qt中的QString和QStringList常用方法
    Qt界面编程基本操作
    vs+qt编程相关
    C++的一些关键字用法
    Java学习-hashcode综合练习
    Java学习-HashMap练习
    Java学习-HashSet练习
    Java学习-HashMap性能简单测试
    Java学习-排序二叉树性能简单测试
    java学习-排序二叉树
  • 原文地址:https://www.cnblogs.com/h-lka/p/12592870.html
Copyright © 2011-2022 走看看