P3521 [POI2011]ROT-Tree Rotations(线段树合并+权值线段树,好题)


题目链接:

洛谷 P3521 [POI2011]ROT-Tree Rotations
loj 「POI2011 R2 Day2」旋转树木 Tree Rotations(数据加强过)
都是同一个题。


题解

讲真这题不看题解,我还不太会写出来,涉及树的合并操作,有点不太会。
PS:这篇博客放在草稿箱好久,主要是之后我还要补树的合并的相关知识,当时对那个merge函数了解不是很清晰

1、左右子树的交换不影响节点,只要两种情况取最小即可。
2、确定左右子树是否交换后,又和子树合并的操作。
3、add函数还是权值线段树的模板,merge函数是树合并的操作
4、这里的输入有点特别,可以用dfs来读取这些叶子节点。

void dfs(int &i){
	x=read();
	int ls,rs;
	if(!x){
		dfs(ls=0);	dfs(rs=0);
		a=b=0;	i=ls;
		merge(i,rs);
		ans+=min(a,b);
	}
	else	add(i,1,n);
}

ac的部分代码

#define mid		((l+r)>>1)
const int maxn=4e6+5;
int n,rt,cnt,x;
int sum[maxn],t[maxn][2];
ll a,b,ans;
void add(int &i,int l,int r){
	i=++cnt;	sum[i]++;
	if(l==r)	return;
	if(x<=mid)	add(t[i][0],l,mid);
	else		add(t[i][1],mid+1,r);
}
void merge(int &i,int j){
	if(!i||!j){
		i=i|j;
		return;
	}
	sum[i]+=sum[j];
	a+=(ll)sum[t[i][0]]*sum[t[j][1]];
	b+=(ll)sum[t[i][1]]*sum[t[j][0]];
	merge(t[i][0],t[j][0]);
	merge(t[i][1],t[j][1]);
}
void dfs(int &i){
	x=read();
	int ls,rs;
	if(!x){
		dfs(ls=0);	dfs(rs=0);
		a=b=0;	i=ls;
		merge(i,rs);
		ans+=min(a,b);
	}
	else	add(i,1,n);
}
int main(){
	n=read();
	dfs(rt);
	printf("%lld",ans);
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值