CF #301 E:Infinite Inversions(逆序数,树状数组)
A-Combination Lock B-School Marks C-Ice Cave D-Bad Luck Island E-Infinite Inversions
题意就是有一个序列1,2,3,4。。。。。
现在有n次交换,每次都把ab交换求最终形成的序列的逆序数;
逆序数分为两部分。一部分是交换过位置的,另一部分是没有交换过的。
离散化后,利用树状数组求出交换过的位置的逆序数的个数。
第二部分:
看一个样例:
2
1 6
9 5
得到的序列为6 2 3 4 9 1 7 8 5
首先对于数值6,其下标为1。在区间[1, 6]中,共有6个数。减去该区间中有3个是交换过位置的,则6-3 = 3是数值6对于当前序列所构成的逆序数个数。
对于数值9,下标为5,则在区间[5,9],共有5个数。减去该区间有3个是换过位置的,则逆序数为2。
对于数值1,其下标为6,在区间[1,6]中,~~~~~也有3个逆序数。
……
问题变为求一个区间的中有几个是交换过位置的,其实只要知道其下标的排名。例如下标1的排名为1,下标5排名2,下标6排名3,下标9排名4。
区间[1,6],则是3-1+1 = 3;
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<map> #include<cmath> #include<queue> using namespace std; #define N 2010005 #define INF 0x3f3f3f3f struct node { int x, y; }b[N]; map<int, int>M; int a[N], cnt, Tree[N], V[N]; int lowbit(int x) { return x&(-x); } void Update(int pos, int num) { while(pos<=cnt) { Tree[pos]+=num; pos+=lowbit(pos); } } int GetSum(int pos) { int s=0; while(pos) { s+=Tree[pos]; pos-=lowbit(pos); } return s; } int main() { int n; while(scanf("%d", &n)!=EOF) { memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); memset(V, 0, sizeof(V)); cnt=1; for(int i=0; i<n; i++) { scanf("%d %d", &b[i].x, &b[i].y); a[cnt++]=b[i].x, a[cnt++]=b[i].y; } sort(a+1, a+cnt); cnt = unique(a, a+cnt)-a-1; for(int i=1; i<=cnt; i++) M[a[i]]=i, V[i]=i; for(int i=0; i<n; i++) { int p=M[b[i].x]; int q=M[b[i].y]; swap(V[p], V[q]); } long long ans=0; memset(Tree, 0, sizeof(Tree)); for(int i=1; i<=cnt; i++) { int x=V[i]; ans+=(i-1-GetSum(x)); Update(x, 1); } for(int i=1; i<=cnt; i++) ans+=abs(a[V[i]]-a[i]-V[i]+i); printf("%lld\n", ans); } return 0; }