(传送门)
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;
}