Infinite Inversions CodeForces - 540E(树状数组+离散化)

这篇博客介绍了一种利用离散化和树状数组来计算序列经过多次交换操作后的逆序对数量的方法。首先对输入的交换操作进行排序和去重,然后通过下标转换将交换位置转换为离散序列中的位置。接着,通过临时数组模拟交换过程,同时记录交换间隔。最后,利用树状数组动态维护逆序对计数,得出最终答案。该方法巧妙地结合了数据结构和算法,有效地解决了复杂问题。
摘要由CSDN通过智能技术生成

Infinite Inversions CodeForces - 540E题目

There is an infinite sequence consisting of all positive integers in the increasing order: p = {1, 2, 3, …}. We performed n swap operations with this sequence. A swap(a, b) is an operation of swapping the elements of the sequence on positions a and b. Your task is to find the number of inversions in the resulting sequence, i.e. the number of such index pairs (i, j), that i < j and pi > pj.
Input

The first line contains a single integer n (1 ≤ n ≤ 105) — the number of swap operations applied to the sequence.

Each of the next n lines contains two integers ai and bi (1 ≤ ai, bi ≤ 109, ai ≠ bi) — the arguments of the swap operation.
Output

Print a single integer — the number of inversions in the resulting sequence.
Examples
Input

2
4 2
1 4

Output

4

Input

3
1 6
3 4
2 5

Output

15

题目网址

链接: https://codeforces.com/problemset/problem/540/E.

想法

总体的想法:
1.将输入的L R放入一个数组并且排序,去重。
2.根据形成的数组,将每个query的LR修改为形成数组的下表。
3.声明一个新的数组tmp,并且按照修改后query的L ,R来实现交换,并形成一个结果数组1。
4.便利结果数组1,并且将他放入结果数组2中(由于结果数组1是交换后的,所以将pos中交换的间隔放入结果数组2中)
5.使用树状数组计算逆序对数量。

其实就是离散化+额外计算一下中间为参与交换的部分。只不过想起来会比较绕

代码

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 1e5 + 1e3; 
typedef long long int LL; 
struct Node{
	int l , r;
}query[N];//询问数组
struct Node1{
	int pos;
	LL val;
}res[N<<2];//结果数组2
int n , pos[N<<1] , tmp[N<<1] , m;//pos为第二步形成的数组,tmp为结果数组1
LL cnum[N<<2];//树状数组使用的数组,由于原本L~R为N,所以L,R加起来最多为2N,
//再计算一下中间部分,最多为4*N
int lowbit(int x){
	return x&(-x);
}
LL getSum(int index){
	LL res = 0;
	for(int i = index ; i > 0 ; i -= lowbit(i) ){
		res += cnum[i];
	}
	return res;
}
void add(int index , int num){
	for(int i = index ; i <= m ; i += lowbit(i)){
		cnum[i] += num;
	}
}
int main(){
	ios::sync_with_stdio(false);
	int i , j ;
	cin>>n;
	for(i = 1 , j = 0 ; i <= n ; i ++ ){
		cin>>query[i].l>>query[i].r;
		pos[++j] = query[i].l;pos[++j] = query[i].r;
	}
	sort(pos+1,pos+1+j);
	int len = unique(pos+1,pos+1+j)-pos-1;
	for(i = 1 ; i <= n ; i ++ ){
		query[i].l = lower_bound(pos+1,pos+1+len,query[i].l)-pos;
		query[i].r = lower_bound(pos+1,pos+1+len,query[i].r)-pos;
	}
	for(i = 1 ; i <= len ; i ++ ) tmp[i] = i;
	for(i = 1 ; i <= n ; i ++ ){
		swap(tmp[query[i].l],tmp[query[i].r]);
	}
	int tot = 0;
	for(i = 1 ; i <= len ; i ++ ){
		if(pos[i-1]+1<=pos[i]-1){
			++tot;
			res[tot].pos = i*2-1;
			res[tot].val = (LL)(pos[i]-pos[i-1]-1);
		}
		++tot;
		res[tot].pos = tmp[i]*2;
		res[tot].val = 1;
	}
	m = len*2;
	LL reser = 0;
	for(i = 1 ; i <= tot ; i ++ ){
		reser += (getSum(m)-getSum(res[i].pos))*res[i].val;
		add(res[i].pos , res[i].val);
	}
	cout<<reser<<endl;
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值