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

    [ exttt{Description} ]

    给定一棵 (n) 个点的树,每个点有一个颜色( "黑" 或 "白" )。

    对于每个点 (x) ,求出所有包含点 (x) 的联通子图中,白点数减去黑点数的最大值是多少。

    [ exttt{Solution} ]

    • 树形 dp 好题。
    • 首先我们随便找一个点定个根,就以 (1) 为根吧。
    • (f_x) 表示:在以 (x) 为根的子树内,所有包含点 (x) 的联通子图中,白点数减去黑点数的最大值。
    • 对于点 (u) 的每个儿子 (v) ,若 (f_v) 没有产生负贡献,则可以计入 (f_u) 中,再结合 (u) 点自身,不难得到转移:

    [f_u = egin{cases} sumlimits_{v in ext{son(u)}}max(f_v,0)-1 & col_u = exttt{black} \ sumlimits_{v in ext{son(u)}}max(f_v,0)+1 & col_u = exttt{white} end{cases} ]

    • 从下至上树形 dp 即可求出 (f)
    • 接下来就是换根 dp 了,设 (g_x) 表示:所有包含点 (x) 的联通子图中,白点数减去黑点数的最大值。
    • 首先可以确定的是 (g_{root}=f_{root})
    • 我们发现刨去以 (x) 为根的子树,剩下这部分比较难求答案。
    • 刨去以 (x) 为根的子树给我们启发,仔细思考便知 (max(g_{fa}-max(f_u,0),0)) 即为刨去以 (x) 为根的子树,剩下部分的答案,不难得到转移:

    [g_u = egin{cases} f_u & u= exttt{root} \ f_u +max(g_{fa}-max(f_u,0),0) & u eq exttt{root} end{cases} ]

    • 从上至下换根 dp 即可求出 (g)
    • (mathcal{O(n)})评测链接

    [ exttt{Code} ]

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    
    #define RI register int
    
    using namespace std;
    
    namespace IO
    {
        static char buf[1<<20],*fs,*ft;
        inline char gc()
        {
            if(fs==ft)
            {
    			ft=(fs=buf)+fread(buf,1,1<<20,stdin);
    			if(fs==ft)return EOF;
            }
            return *fs++;
        }
        #define gc() getchar()
    	inline int read()
    	{
    		int x=0,f=1;char s=gc();
    		while(s<'0'||s>'9'){if(s=='-')f=-f;s=gc();}
    		while(s>='0'&&s<='9'){x=x*10+s-'0';s=gc();}
    		return x*f;
    	}
    }using IO::read;
    
    const int N=200100,M=400100;
    
    int n;
    
    int a[N];
    
    int tot,head[N],ver[M],Next[M];
    
    void add(int u,int v)
    {
    	ver[++tot]=v;    Next[tot]=head[u];    head[u]=tot;
    }
    
    int f[N];
    
    int g[N];
    
    void calc(int u,int fu)
    {
    	if(a[u]==1)
    		f[u]++;
    	else
    		f[u]--;
    
    	for(RI i=head[u];i;i=Next[i])
    	{
    		int v=ver[i];
    
    		if(v==fu)continue;
    
    		calc(v,u);
    
    		if(f[v]>0)
    			f[u]+=f[v];
    	}
    }
    
    bool vis[N];
    
    void bfs()
    {
    	queue<int>q;
    
    	q.push(1);
    	g[1]=f[1];
    	vis[1]=true;
    
    	while(q.size())
    	{
    		int u=q.front();q.pop();
    
    		for(RI i=head[u];i;i=Next[i])
    		{
    			int v=ver[i];
    
    			if(vis[v])
    				continue;
    
    			g[v]=f[v]+max(0,g[u]-max(0,f[v]));
    
    			vis[v]=true;
    			q.push(v);
    		}
    	}
    }
    
    int main()
    {
    	n=read();
    
    	for(RI i=1;i<=n;i++)
    		a[i]=read();
    
    	for(RI i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		add(u,v),add(v,u);
    	}
    
    	calc(1,0);
    
    	bfs();
    
    	for(RI i=1;i<=n;i++)
    		printf("%d ",g[i]);
    	puts("");
    
    	return 0;
    }
    

    [ exttt{Thanks} exttt{for} exttt{watching} ]

  • 相关阅读:
    最常被程序员们谎称读过的计算机书籍
    天气城市代码,市级城市. 用java的map.中国天气网.
    你所知道的学习方法,都是错的!
    解决「问题」,不要解决问题
    [IOS 下重温设计模式] AbstractFactory
    判断UIView是否装载完成
    va_start、va_end、va_list的使用
    [IOS 下重温设计模式] Singleton
    IOS BLOCK收集
    SEL
  • 原文地址:https://www.cnblogs.com/cjtcalc/p/12485536.html
Copyright © 2011-2022 走看看