P3521 [POI2011]ROT-Tree Rotations [权值线段树合并]

传送门

我们发现交换两个子树, 两个子树内部是不会变的, 于是贪心考虑该子树换不换

于是我们建权值线段树, 不换的话逆序对就是左儿子的权值线段树的右儿子 * 右儿子的权值线段树的左儿子, 换了相反

于是我们边统计边合并两颗权值线段树

大致过程 [蒟蒻第一次学权值线段树合并]

 代码大概是这样

void Merge(int &x,int y){// 将y合并到x上
    if(!x||!y){x = x+y; return;} // 有一个为空就没有必要继续递归了,如果x为空,x继承y就可以了
    t[x].val += t[y].val; // 两个子树个数累加
    Merge(t[x].ls, t[y].ls); // 递归合并
    Merge(t[x].rs, t[y].rs);
}

叶子节点(n个)每个插入权值线段树要logn个节点, 所以空间是nlogn的


#include<bits/stdc++.h>
#define N 200050
#define LL long long
using namespace std;

struct Node{
	int ls,rs,val;
}t[N*40];
LL sum1,sum2,ans;

int n,tot;
void Modify(int &x,int l,int r,int pos){
	if(!x) x = ++tot; t[x].val++;
	if(l==r) return;
	int mid = (l+r) >> 1;
	if(pos<=mid) Modify(t[x].ls,l,mid,pos);
	else Modify(t[x].rs,mid+1,r,pos);
}
void Merge(int &x,int y){
	if(!x||!y){ x = x+y; return;}
	t[x].val += t[y].val;
	sum1 += (LL)t[t[x].rs].val * (LL)t[t[y].ls].val;
	sum2 += (LL)t[t[x].ls].val * (LL)t[t[y].rs].val;
	Merge(t[x].ls, t[y].ls);
	Merge(t[x].rs, t[y].rs);
}
void Solve(int &pos){
	int x; scanf("%d",&x);
	if(x==0){
		int ls=0, rs=0;
		Solve(ls); Solve(rs);
		sum1=0, sum2=0;
		pos = ls; Merge(pos,rs);
		ans += min(sum1, sum2);
	}
	else Modify(pos,1,n,x);
}
int main(){
	scanf("%d",&n); int tmp = 0;
	Solve(tmp); printf("%lld",ans); 
	return 0;
} 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值