codeforces1363E Tree Shuffling

https://codeforces.com/problemset/problem/1363/E

这题一看到子树,立刻想到dfs序,然后直接dfs序搞线段树打区间标记,bit维护区间剩余换0的个数和换1的个数,然后把点按ai排序搞就行了。因为一个cost更小的点,肯定是它能处理的尽量处理,然后如果当前这个枚举的点被某个ai更小点曾经处理过这个dfs序的区间了,说明那个ai更小的点是它的父节点,他就什么都不能干。这个点把他能处理的处理完之后,在dfn[id]的位置减去处理的个数,01都减,因为如果之后他的某个父节点要求值时,dfs序的区间会包括他的区间,dfn[id]这个位置肯定包含其中,那么就能求出当前这个点最多能处理多少点了。

然后写了一个小时wa了。。。

在查错的时候,发现我只要考虑每个不同的点被哪个祖先点给处理就行了。。。于是直接dfs向下,维护当前点和所有祖先点的最小值val,然后当前子树剩余的要换的0和要换的1取个最小值,就是要处理的点,用val乘他们就行了。。。这个写法10分钟就写完了。。。还好最后过了,不然能气死

还是太菜了,应该想更简单的办法的,不应该冲动

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=3e5+10;

int n,m,cas,k,ind,sum1,sum2;
int b[maxl],c[maxl],dfn[maxl],out[maxl];
int q[2][maxl];
char s[maxl];
bool in[maxl],vis[maxl];
vector<int> e[maxl];
struct node
{
	int l,r,tag;
}tree[maxl*4];
ll bit[2][maxl],sum[2][maxl];
ll ans;
struct tn
{
	int id,val;
}a[maxl];

inline void dfs(int u,int fa,int val)
{
	vis[u]=true;dfn[u]=++ind;
	if(b[u]!=c[u])
	{
		q[c[u]][u]++;sum[c[u]][u]=1;
	}
	ll mi,now,tot=0;
	for(int v:e[u])
	{
		if(v==fa) continue;
		dfs(v,u,min(val,a[v].val));
		sum[0][u]+=sum[0][v];
		sum[1][u]+=sum[1][v];
	}
	mi=min(sum[0][u],sum[1][u]);
	sum[0][u]-=mi;sum[1][u]-=mi;
	ans+=mi*val*2;
}

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&a[i].val,&b[i],&c[i]);
		a[i].id=i;
	}
	int u,v;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	ans=0;
	dfs(1,0,a[1].val);
	for(int i=1;i<=n;i++)
	{
		if(q[0][i])
			sum1++;
		if(q[1][i])
			sum2++;
	}
	if(sum1!=sum2)
		ans=-1;
} 

inline void mainwork()
{
	
}

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=3e5+10;

int n,m,cas,k,ind,sum1,sum2;
int b[maxl],c[maxl],dfn[maxl],out[maxl];
int q[2][maxl];
char s[maxl];
bool in[maxl],vis[maxl];
vector<int> e[maxl];
struct node
{
	int l,r,tag;
}tree[maxl*4];
ll bit[2][maxl];
ll ans;
struct tn
{
	int id,val;
}a[maxl];

inline void dfs(int u,int fa)
{
	vis[u]=true;dfn[u]=++ind;
	if(b[u]!=c[u])
		q[c[u]][u]++;
	ll mi,now,tot=0;
	for(int v:e[u])
	{
		if(v==fa) continue;
		dfs(v,u);
	}
	out[u]=ind;
}

inline void add(int i,int x,int id)
{
	while(i<=n)
	{
		bit[id][i]+=x;
		i+=i&-i;
	}
}

inline ll sum(int i,int id)
{
	ll ret=0;
	while(i)
	{
		ret+=bit[id][i];
		i-=i&-i;
	}
	return ret;
}

inline void build(int k,int l,int r)
{
	tree[k].l=l;tree[k].r=r;
	if(l==r)
	{
		tree[k].tag=0;
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&a[i].val,&b[i],&c[i]);
		a[i].id=i;
	}
	int u,v;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1,0);
	build(1,1,n);
	sum1=0,sum2=0;
	for(int i=1;i<=n;i++)
	{
		if(q[0][i])
			add(dfn[i],1,0),sum1++;
		if(q[1][i])
			add(dfn[i],1,1),sum2++;
	}
} 

inline void upd(int k,int l,int r)
{
	if(tree[k].l==l && tree[k].r==r)
	{
		tree[k].tag=1;
		return;
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(r<=mid)
		upd(k<<1,l,r);
	else if(l>mid)
		upd(k<<1|1,l,r);
	else
	{
		upd(k<<1,l,mid);
		upd(k<<1|1,mid+1,r);
	}
}

inline bool qry(int k,int l)
{
	if(tree[k].l==tree[k].r)
		return tree[k].tag;
	if(tree[k].tag) return true;
	int mid=(tree[k].l+tree[k].r)>>1;
	if(l<=mid)
		return qry(k<<1,l);
	else
		return qry(k<<1|1,l);
}

inline bool cmp(const tn &x,const tn &y)
{
	return x.val<y.val;
}

inline void mainwork()
{
	if(sum1!=sum2)
	{
		ans=-1;
		return;
	}
	sort(a+1,a+1+n,cmp);
	ll t0,t1,d,id;
	for(int i=1;i<=n;i++)
	{
		id=a[i].id;
		if(qry(1,dfn[id])) continue;
		t0=sum(out[id],0)-sum(dfn[id]-1,0);
		t1=sum(out[id],1)-sum(dfn[id]-1,1);
		d=min(t1,t0);
		add(dfn[id],-d,0);
		add(dfn[id],-d,1);
		upd(1,dfn[id],out[id]);
		ans+=1ll*a[i].val*d*2;
	}
}

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值