zoukankan      html  css  js  c++  java
  • 题解[Lougu P5521 [yLOI2019] 梅深不见冬]

    题意

    Link

    不会概括

    Solution

    对于一个节点(u):

    如果(u)是叶子节点,(ans_u=w_u)

    如果不是:

    假设我们已经知道了(u)所有儿子节点(v_i)的答案,我们需要安排一个合理的顺序,让放梅花过程中的最大值最小。而且由题目性质可知一定是先解决一颗子树,再去解决另一棵。

    再假设我们已经定好了顺序,那么过程中的最大值就是之前所有儿子的权值和+当前儿子的答案。节点的答案>=节点的权值,所以这里有一个差量

    这里的差量=答案-权值。

    我们发现如果差量越大,中间过程的浪费就越严重,所以应尽量让差量大的在前,于是贪心策略就出来了。

    按儿子节点的差量由大到小排序,扫一遍就可以了(≧▽≦)/啦啦啦

    Code

    一个错误的写法,挂上引以为戒。

    #include<bits/stdc++.h>
    #define N (200010)
    using namespace std;
    struct xbk{int a,b;}now[N],ans[N];
    struct edge{int nx,ed;}e[N];
    int n,cnt,head[N];
    vector<int>v[N];
    inline int read(){
    	int w=0;
    	char ch=getchar();
    	while(ch>'9'||ch<'0') ch=getchar();
    	while(ch>='0'&&ch<='9'){
    		w=(w<<3)+(w<<1)+(ch^48);
    		ch=getchar();
    	}
    	return w;
    }
    inline bool cmp(xbk aa,xbk bb){return aa.b-aa.a>bb.b-bb.a;}
    inline void add(int a,int b){
    	e[++cnt].ed=b;
    	e[cnt].nx=head[a];
    	head[a]=cnt;
    }
    inline void dfs(int st){
    	int tot=0;	
            for(int i=head[st];i;i=e[i].nx){
    	    int ed=e[i].ed;
                dfs(ed);
    	}
    	if(!(int)v[st].size()){
    	        ans[st].b=ans[st].a;
    		return;
    	}
    	for(int i=0;i<(int)v[st].size();i++) now[++tot]=ans[v[st][i]];
    	sort(now+1,now+1+tot,cmp);
    	int nw=0,sum=0;
    	now[0].a=0,now[0].b=0;
    	now[tot+1]=now[0];
    	for(int i=1;i<=tot+1;i++)
    		nw=max(nw,nw-now[i-1].b+now[i-1].a+now[i].b),sum+=now[i].a;
    	ans[st].b=max(nw,sum+ans[st].a);
    	return;
    }
    int main(){
    	n=read();
    	for(int i=2;i<=n;i++){
    		int u=read();
    		add(u,i);
    		v[u].push_back(i);
    	}
    	for(int i=1;i<=n;i++) ans[i].a=read();
    	dfs(1);
    	for(int i=1;i<=n;i++){
    		printf("%d ",ans[i].b);
    	}
    	puts("");
    	return 0;
    }
    

    正解

    #include<bits/stdc++.h>
    #define N (100010)
    using namespace std;
    struct xbk{int a,b;}ans[N];
    int n,cnt,head[N];
    vector<int>v[N];
    inline int read(){
    	int w=0;
    	char ch=getchar();
    	while(ch>'9'||ch<'0') ch=getchar();
    	while(ch>='0'&&ch<='9'){
    		w=(w<<3)+(w<<1)+(ch^48);
    		ch=getchar();
    	}
    	return w;
    }
    inline bool cmp(xbk aa,xbk bb){return aa.b-aa.a>bb.b-bb.a;}
    inline void dfs(int st){
    	int tot=(int)v[st].size();
    	int nw=0,sum=ans[st].a;
    	for(int i=0;i<tot;i++) sum+=ans[v[st][i]].a,dfs(v[st][i]);
    	if(!tot){
    		ans[st].b=ans[st].a;
    		return;
    	}
    	xbk now[tot+10];
    	memset(now,0,sizeof(now));
    	for(int i=0;i<tot;i++) now[i+1]=ans[v[st][i]];
    	sort(now+1,now+1+tot,cmp);
    	for(int i=1;i<=tot;i++){
    		ans[st].b=max(ans[st].b,nw+now[i].b);
    		nw+=now[i].a;
    		ans[st].b=max(ans[st].b,sum);
    	}
    	return;
    }
    int main(){
    	n=read();
    	for(int i=2;i<=n;i++){
    		int u=read();
    		v[u].push_back(i);
    	}
    	for(int i=1;i<=n;i++) ans[i].a=read();
    	dfs(1);
    	for(int i=1;i<=n;i++)
    		printf("%d ",ans[i].b);
    	puts("");
    	return 0;
    }
    
    

    撒花!!!

  • 相关阅读:
    带字数限制提示的输入框效果
    js快速获取数组中的最大值最小值
    js实现连线题
    js自定义图片提示效果
    为了遇见你
    为了明天(励志篇)
    你为什么总是不理我
    爱情,是我一生中最虔诚的信仰
    你是我心中永远抹不掉的痛
    爱你一万次够不够
  • 原文地址:https://www.cnblogs.com/xxbbkk/p/14269565.html
Copyright © 2011-2022 走看看