题目描述
逝者如斯夫,不舍昼夜!叶良辰认为,他的寿命是无限长的,而且每天都会进步。
叶良辰的生命的第一天,他有1点能力值。第二天,有2点。第n天,就有n点。也就是S[i]=i
但是调皮的小A使用时光机,告诉他第x天和第y天,就可以任意交换某两天的能力值。即S[x]<-->S[y]
小A玩啊玩,终于玩腻了。
叶良辰:小A你给我等着,我有100种办法让你生不如死。除非能在1秒钟之内告知有多少对“异常对”。也就是说,最后的能力值序列,有多少对的两天x,y,其中x<y,但是能力值S[x]>S[y]?
小A:我好怕怕啊。
于是找到了你。
输入输出格式
输入格式: 第一行一个整数k,表示小A玩了多少次时光机
接下来k行,x_i,y_i,表示将S[x_i]与S[y_i]进行交换
有多少“异常对”
输入输出样例
输入样例#1:2 4 2 1 4输出样例#1:
4
说明
样例说明最开始是1 2 3 4 5 6...
然后是 1 4 3 2 5 6...
然后是 2 4 3 1 5 6...
符合的对是[1 4] [2 3] [2 4] [3 4]
对于30%的数据,x_i,y_i <= 2000
对于70%的数据, x_i,y_i <= 100000
对于100%的数据, x_i.y_i <= 2^31-1 k<=100000
思路:树状数组求逆序对。但是数据太大,直接做会超。于是,发现找区间的逆序对和点的逆序对之和就是所要求的答案。离散化一下,1、统计当前i(离散后的值)和i+1(同)的区间长度x*sum[ i ](i之后小于等于i的数),然后更新sum[ i ](+x),2、再统计点的逆序对(正常求法)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=2*100005;
ll ans=0,ha[maxn],q1[maxn],q2[maxn],a[maxn],sum[maxn];
int n,p[maxn],t=0,cnt=0;
inline int get(){
char c;while(!isdigit(c=getchar()));
int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
return v;
}
inline int getpos(int x){
int l=1,r=cnt;
while(l<r){
int mid=(l+r)>>1;
if(x<=ha[mid])r=mid;
else l=mid+1;
}
return l;
}
inline int lowbit(int x){return (x&(-x));}
inline void add(int x,ll y){
while(x<=cnt){
sum[x]+=y;
x+=lowbit(x);
}
}
inline ll getsum(int x){
ll ret=0;
while(x){
ret+=sum[x];
x-=lowbit(x);
}
return ret;
}
int main(){
n=get();memset(sum,0,sizeof(sum));
for(int i=1;i<=n;++i)a[++t]=q1[i]=get(),a[++t]=q2[i]=get();
sort(a+1,a+1+t);
for(int i=1;i<=t;++i)if(a[i]!=a[i-1])ha[++cnt]=a[i];
for(int i=1;i<=cnt;++i)p[i]=i;
for(int i=1;i<=n;++i){
int x=getpos(q1[i]),y=getpos(q2[i]);
int tt=p[x];p[x]=p[y];p[y]=tt;
}
add(p[cnt],1);
for(int i=cnt-1;i>=1;--i){
ll x=(ha[i+1]-ha[i]-1),y=getsum(i);
ans+=x*y;
add(i,x);
ans+=getsum(p[i]-1);
add(p[i],1);
}
printf("%lld\n",ans);
return 0;
}