码迷,mamicode.com
首页 > 其他好文 > 详细

agc023F - 01 on Tree

时间:2020-11-20 11:41:40      阅读:5      评论:0      收藏:0      [点我收藏+]

标签:stdout   bool   --   def   turn   fclose   img   经典   没有   

题目描述

技术图片

题解

经典魔塔模型(

设(ai,bi)表示一个块的0/1个数,块i在块j前满足biaj<bjai,化一下变成ai/bi>aj/bj

如果没有树的限制就直接选,否则如果有一个劣的节点在上面,优的节点在下面,则选完劣的后必须要选优的,可以把优的和其父亲合并,注意相同时要先合并上面的

用堆从大到小搞,合并完之后的树满足其儿子一定更劣,所以贪心选即可

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
//#define file
using namespace std;

struct type{ll a,b;int id;} c[200001],s;
int Fa[200001],fa[200001],b[200001],n,i,j,k,l;
bool bz[200001];
ll ans,sum;

bool operator < (type a,type b) {return !(a.b*b.a<b.b*a.a || a.b*b.a==b.b*a.a && a.id<b.id);}
bool cmp(type a,type b) {return a.b*b.a<b.b*a.a;}
priority_queue<type> hp;

int gf(int t) {if (fa[t]==t) return t; fa[t]=gf(fa[t]);return fa[t];}

int main()
{
	#ifdef file
	freopen("agc023F.in","r",stdin);
//	freopen("b.out","w",stdout);
	#endif
	
	scanf("%d",&n);
	fo(i,2,n) scanf("%d",&Fa[i]);
	fo(i,1,n) scanf("%d",&b[i]),sum+=!b[i],c[i].a=b[i]==0,c[i].b=b[i]==1,c[i].id=i,fa[i]=i;
	fd(i,n,1)
	if (!b[i]) c[Fa[i]].a+=c[i].a,fa[i]=Fa[i],bz[i]=1; else hp.push(c[i]),ans+=c[i].a;
	sum-=c[0].a;
	
	while (!hp.empty())
	{
		s=hp.top(),hp.pop();
		if (c[s.id].b!=s.b) continue;
		
		j=gf(Fa[gf(s.id)]);
		if (j && cmp(s,c[j]))
		{
			ans+=c[j].b*s.a;
			c[j].a+=s.a,c[j].b+=s.b;
			fa[s.id]=j,hp.push(c[j]);
			bz[s.id]=1;
		}
	}
	fo(i,1,n) if (!bz[i]) hp.push(c[i]),j=gf(Fa[j]);
	while (!hp.empty())
	{
		s=hp.top(),hp.pop();
		sum-=s.a,ans+=s.b*sum;
	}
	printf("%lld\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}

agc023F - 01 on Tree

标签:stdout   bool   --   def   turn   fclose   img   经典   没有   

原文地址:https://www.cnblogs.com/gmh77/p/13976798.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!