题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=180
解题报告:一个裸的求逆序对的题,离散化+线段树,也可以用离散化+树状数组。因为这题中的数列有重复的而且范围特别大,所以要进行离散化,离散化的方法是,
首先按照输入的数字排个序,然后把整个数列扫一遍,得出每个数字离散化的结果,然后再按照输入的顺序把顺序调整回来就OK 了。线段树部分就不说了。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 typedef __int64 INT; 7 const int maxn = 65537+5; 8 9 struct node 10 { 11 int data,cixu,dd; 12 }que[maxn]; 13 14 struct Node 15 { 16 INT data; 17 int l,r; 18 }tree[2*maxn]; 19 20 bool cmp1(node a,node b) 21 { 22 return a.data <= b.data; 23 } 24 bool cmp2(node a,node b) 25 { 26 return a.cixu < b.cixu; 27 } 28 void maketree(int p) 29 { 30 if(tree[p].l == tree[p].r) 31 return ; 32 int mid = (tree[p].l + tree[p].r) / 2; 33 tree[2*p].data = 0; 34 tree[2*p].l = tree[p].l; 35 tree[2*p].r = mid; 36 maketree(2*p); 37 tree[2*p+1].data = 0; 38 tree[2*p+1].l = mid + 1; 39 tree[2*p+1].r = tree[p].r; 40 maketree(2*p+1); 41 } 42 INT find(int p,int l,int r) 43 { 44 if(l > r) 45 return 0; 46 if(tree[p].l == l && tree[p].r == r) 47 return tree[p].data; 48 int mid = (tree[p].l + tree[p].r) / 2; 49 if(r <= mid) 50 return find(2*p,l,r); 51 else if(l <= mid && r > mid) 52 return find(2*p,l,mid) + find(2*p+1,mid + 1,r); 53 else return find(2*p+1,l,r); 54 } 55 void push(int p,int d) 56 { 57 tree[p].data++; 58 if(tree[p].l == tree[p].r) 59 return ; 60 int mid = (tree[p].l + tree[p].r) / 2; 61 if(d <= mid) 62 push(2*p,d); 63 else push(2*p+1,d); 64 } 65 int main() 66 { 67 int n; 68 scanf("%d",&n); 69 for(int i = 1;i <= n;++i) 70 { 71 scanf("%d",&que[i].data); 72 que[i].cixu = i; 73 } 74 sort(que+1,que+n+1,cmp1); 75 int f = -1; 76 que[0].data = 0x7fffffff; //只要一个跟所有输入的数都不同的就行了 77 for(int i = 1;i <= n;++i) 78 { 79 if(que[i].data != que[i-1].data) 80 f++; 81 que[i].dd = f; 82 } 83 tree[1].data = 0; 84 tree[1].l = 0; 85 tree[1].r = f; 86 maketree(1); 87 sort(que+1,que+n+1,cmp2); 88 INT tot = 0; 89 for(int i = 1;i <= n;++i) 90 { 91 tot += find(1,que[i].dd + 1,f); 92 push(1,que[i].dd); 93 } 94 printf("%I64d\n",tot); 95 return 0; 96 }