CF 540E-Infinite Inversions-区间离散+线段树

(传送门)

Description

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

For each test case, print a single line containing an integer, denoting the maximum total value.

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.

Sample Input1

2
4 2
1 4

Sample Output1

4

Sample Input2

3
1 6
3 4
2 5

Sample Output2

15

核心思想:

离散化+线段树
如何离散和建树见本人另一篇博文:
https://blog.csdn.net/Nothing_but_Fight/article/details/98471932
此题的区间将离散为带权值的点

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+20;
char s[20];
int b[N<<2],cnt;//b数组存离散前后大小关系的映射 
ll v[N<<2];//v数组存离散前后相应数值的个数 
struct node{
	int x,id;
}a[N<<2];
struct Node{
	int x,y;
}ru[N];
struct tnode{
	int l,r;
	ll sum;
}tr[N<<4];
void pushup(int m)
{
	tr[m].sum=tr[m<<1].sum+tr[m<<1|1].sum;
	return;
}
void build(int m,int l,int r)
{
	tr[m].l=l;
	tr[m].r=r;
	if(l==r)
	{
		tr[m].sum=0;
		return;
	}
	int mid=(l+r)>>1;
	build(m<<1,l,mid);
	build(m<<1|1,mid+1,r);
	pushup(m);
	return;
}
void update(int m,int x,ll v)
{
	if(tr[m].l==x&&tr[m].r==x)
	{
		tr[m].sum=v;
		return;
	}
	int mid=(tr[m].l+tr[m].r)>>1;
	if(x<=mid)
		update(m<<1,x,v);
	else
		update(m<<1|1,x,v);
	pushup(m);
	return;
}
ll query(int m,int l,int r)
{
	if(tr[m].l==l&&tr[m].r==r)
		return tr[m].sum;
	int mid=(tr[m].l+tr[m].r)>>1;
	if(r<=mid)
		return query(m<<1,l,r);
	if(l>mid)
		return query(m<<1|1,l,r);
	return query(m<<1,l,mid)+query(m<<1|1,mid+1,r);
}
bool cmp1(node p,node q)
{
	return p.x<q.x;
}
bool cmp2(node p,node q)
{
	return p.x>q.x;
}
int getid(int x)
{
	return lower_bound(b,b+cnt,x)-b+1;
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		int ca=1;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&ru[i].x,&ru[i].y);
			a[ca++].x=ru[i].x;
			a[ca++].x=ru[i].y;
		}
		a[0].x=0;
		sort(a+1,a+ca,cmp1);
		cnt=0;
		//点和区间一起加权离散化 
		for(int i=1;i<ca;i++)
			if(a[i].x-a[i-1].x==1)
			{
				b[cnt]=a[i].x;
				v[cnt]=1;
				cnt++;
			}
			else if(a[i].x-a[i-1].x>1)
			{
				b[cnt]=a[i].x-1;
				v[cnt]=a[i].x-a[i-1].x-1;
				cnt++;
				b[cnt]=a[i].x;
				v[cnt]=1;
				cnt++;
			}
		//a数组表示排列,初始化 
		for(int i=1;i<=cnt;i++)
			a[i].x=a[i].id=i;
		//交换操作 
		for(int i=0;i<n;i++)
		{
			int tx=getid(ru[i].x);
			int ty=getid(ru[i].y);
			int t=a[tx].x;
			a[tx].x=a[ty].x;
			a[ty].x=t;
		}
		//排序,准备让大的先入树 
		sort(a+1,a+cnt+1,cmp2);
		//建树 
		build(1,1,cnt);
		ll ans=0;
		for(int i=1;i<=cnt;i++)
		{
			ans+=query(1,1,a[i].id)*v[a[i].x-1];
			update(1,a[i].id,v[a[i].x-1]);
		}
		printf("%lld\n",ans);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值