http://acm.hdu.edu.cn/showproblem.php?pid=5792
1012 World is Exploding
题意:选四个数,满足a<b and A[a]<A[b] c<d and A[c]>A[d] 问有几个这样的集合
思路:
树状数组+离线化
先处理出每个数左边比它小 大,右边比它大 小的数目,用cnt[][i]表示。最后统计一下减去重复的就可以
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <sstream> 5 #include <string> 6 #include <algorithm> 7 #include <list> 8 #include <map> 9 #include <vector> 10 #include <queue> 11 #include <stack> 12 #include <cmath> 13 #include <cstdlib> 14 using namespace std; 15 typedef long long ll; 16 ll cnt[4][50005]; 17 ll cnt1[50005],cnt2[50005]; 18 ll a[50005]; 19 20 struct Node{ 21 ll num,id; 22 }sub_a[50005]; 23 24 25 ll maxn = 0; 26 ll n; 27 ll tree[100005]; 28 bool cmp(Node a, Node b) { //按照数字排序 29 return a.num < b.num; 30 } 31 void discrete() { //离散化 32 sort(sub_a+1, sub_a+1+n, cmp); 33 a[sub_a[1].id] = 1; 34 maxn = 1; 35 for(ll i = 2; i <= n; i++) { 36 if(sub_a[i].num != sub_a[i-1].num) 37 a[sub_a[i].id] = i; 38 else 39 a[sub_a[i].id] = a[sub_a[i-1].id]; 40 maxn = max(maxn,a[sub_a[i].id]); 41 } 42 } 43 void add(ll k){ 44 while(k <= n){ 45 tree[k] ++; 46 k += k & (- k); 47 } 48 } 49 ll read(ll k){ 50 ll ans = 0; 51 while(k){ 52 ans += tree[k]; 53 k -= k &(-k); 54 } 55 return ans; 56 } 57 58 int main(){ 59 while(scanf("%I64d",&n) != EOF) 60 { 61 memset(cnt1,0,sizeof(cnt1)); 62 memset(cnt2,0,sizeof(cnt2)); 63 for(ll i = 1; i <= n; i ++){ 64 scanf("%I64d",&sub_a[i].num); 65 sub_a[i].id = i; 66 } 67 discrete(); 68 memset(tree,0,sizeof(tree)); 69 //在它右侧比它小的 70 for(ll i = n; i >= 1; i--){ 71 72 add(a[i]); 73 cnt[0][i] = read(a[i] - 1); 74 } 75 //在它左侧比它小的 76 memset(tree,0,sizeof(tree)); 77 for(ll i = 1; i <= n; i ++){ 78 add(a[i]); 79 cnt[1][i] = read(a[i] - 1); 80 a[i] = maxn + 1 - a[i]; 81 } 82 //在它右侧比它大的 83 memset(tree,0,sizeof(tree)); 84 for(ll i = n; i >= 1; i --){ 85 86 add(a[i]); 87 cnt[2][i] = read(a[i] - 1); 88 } 89 //在它左侧比它大的 90 memset(tree,0,sizeof(tree)); 91 for(ll i = 1; i <= n; i ++){ 92 add(a[i]); 93 cnt[3][i] = read(a[i] - 1); 94 a[i] = maxn + 1 - a[i]; 95 } 96 ll cnta = 0,cntb = 0; 97 for(ll i = 1; i <= n; i ++){ 98 cnt1[i] = cnt[0][i] + cnt[3][i]; 99 cnta += cnt1[i]; 100 cnt2[i] = cnt[1][i] + cnt[2][i]; 101 cntb += cnt2[i]; 102 } 103 cnta = cnta / 2; 104 cntb = cntb / 2; 105 long long ans = cnta * cntb; 106 for(ll i = 1; i <= n; i ++){ 107 ans -= cnt1[i] * cnt2[i]; 108 } 109 printf("%I64d ",ans); 110 } 111 return 0; 112 }