CodeForces

来源:互联网 发布:网络推销授权员合同 编辑:程序博客网 时间:2024/06/06 02:55

题目链接


题意:

给一个无限大的递增序列,n次操作,每次操作一组x,y,代表第x位置的数和第y位置的数进行交换,问最后n次交换后存在多少对逆序对。(n<=1e5, x,y<=1e9)


思路:

发现x,y很大,但是n很小可以考虑离散化。但是发现离散化之后每几个数之间未操作的数会对结果影响,所以我们这里就有一个技巧,将每两个要交换的数之间未被操作的一段离散化成一个点,加入到新点钟,再用num[i]记录这一段点的个数,然后就是求逆序对了.


pos[i]表示第i个位置放的是哪一个数,离散化后将所有的交换处理完毕,从后往前遍历一遍更新并统计个数即可.

#include<bits/stdc++.h>#define P pair<int,int>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=4e5+10;int pos[maxn],b[maxn],op[maxn];int num[maxn];int s[maxn];P a[maxn];int lowbit(int x) { return x & -x;}void add(int x,int d){while(x < maxn)s[x] += d,x += lowbit(x);return ;}int sum(int x){int res = 0;while(x)res += s[x],x -= lowbit(x);return res;} int main(){int n;cin>>n;int len = 1;for(int i = 1;i <= n;++i){scanf("%d %d",&a[i].first,&a[i].second);op[len++] = a[i].first;op[len++] = a[i].second;}sort(op+1,op+2*n+1);int cnt = 0;for(int i = 1;i <= 2*n ;++i){if(op[i] == op[i + 1]) continue;b[++cnt] = op[i];num[cnt] = 1;if(op[i] + 1 >= op[i+1]) continue;b[++cnt] = op[i]+1;num[cnt] = op[i+1] - op[i] - 1;}for(int i = 1;i <= cnt;++i) pos[i] = i;for(int i = 1;i <= n;++i){int p1 = lower_bound(b+1,b+cnt+1,a[i].first) - b;int p2 = lower_bound(b+1,b+cnt+1,a[i].second) - b;swap(pos[p1],pos[p2]);}ll ans = 0;for(int i = cnt;i >= 1;--i){ans += (ll)num[pos[i]]*sum(pos[i]);add(pos[i],num[pos[i]]);}printf("%lld\n",ans);return 0;}