BZOJ 3744: Gty的妹子序列 【分块 + 树状数组 + 主席树】
任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3744
3744: Gty的妹子序列
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2571 Solved: 746
[Submit][Status][Discuss]
Description
我早已习惯你不在身边,
人间四月天 寂寞断了弦。
回望身后蓝天,
跟再见说再见……
某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现
她们排成了一个序列,每个妹子有一个美丽度。
Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:"你知道区间
[l,r]中妹子们美丽度的逆序对数吗?"
蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:"强制在线。"
请你帮助一下Autumn吧。
给定一个正整数序列a,对于每次询问,输出al...ar中的逆序对数,强制在线。
Input
第一行包括一个整数n(1<=n<=50000),表示数列a中的元素数。
第二行包括n个整数a1...an(ai>0,保证ai在int内)。
接下来一行包括一个整数m(1<=m<=50000),表示询问的个数。
接下来m行,每行包括2个整数l、r(1<=l<=r<=n),表示询问al...ar中的逆序
对数(若ai>aj且i<j,则为一个逆序对)。
l,r要分别异或上一次询问的答案(lastans),最开始时lastans=0。
保证涉及的所有数在int内。
Output
对每个询问,单独输出一行,表示al...ar中的逆序对数。
Sample Input
4
1 4 2 3
1
2 4
1 4 2 3
1
2 4
Sample Output
2
解题思路:
如果是可以离线的话,直接莫队啦。
但是这里强制在线,就需要分块了。
用 f [ j ][ i ] 维护 第 j 到 第 i 块的右端的答案,这样就省去了 处理块前的那些情况了(论前缀和的美妙)。
预处理 f[ j ][ i ] 的方法就是树状数组直接暴力。
如果 当前区间 【L,R】的 R刚好是某一块的右端点,那么 答案 就是 f [ L ][ pos[ R ] ];
如果不是,那么我们还要处理一下 R 到 前一块右端点的 区间 逆序数,
这里分两部分,第一部分是这一区间与前面的的逆序数,用主席树维护。
第二部分就是这一区间的逆序数了,直接树状数组暴力。
AC code:
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 #define INF 0x3f3f3f3f 6 #define LL long long 7 using namespace std; 8 const int MAXN = 5e4+10; 9 int N, M, cnt, tot, ans; 10 int c1[MAXN], c2[MAXN]; 11 int ch[MAXN*100][2], sum[MAXN*100], a[MAXN], d[MAXN]; 12 int siz, lim, bl[1001], br[1001], pos[MAXN]; 13 int f[MAXN][301], root[MAXN]; 14 15 void add1(int x, int val) //维护小的值 16 { 17 while(x <= N){ 18 c1[x]+=val; 19 x+=(x&(-x)); 20 } 21 } 22 23 void add2(int x, int val) //维护大的值 24 { 25 while(x){ 26 c2[x]+=val; 27 x-=(x&(-x)); 28 } 29 } 30 31 int query1(int x) 32 { 33 int res = 0; 34 while(x){ 35 res+=c1[x]; 36 x-=(x&(-x)); 37 } 38 return res; 39 } 40 41 int query2(int x) 42 { 43 int res = 0; 44 while(x <= N){ 45 res+=c2[x]; 46 x+=(x&(-x)); 47 } 48 return res; 49 } 50 51 void update(int x, int &y, int l, int r, int k) 52 { 53 y = ++tot; 54 ch[y][0] = ch[x][0]; 55 ch[y][1] = ch[x][1]; 56 sum[y] = sum[x]+1; 57 if(l==r) return; 58 int mid = (l+r)/2; 59 if(k<=mid) update(ch[x][0], ch[y][0], l, mid, k); 60 else update(ch[x][1], ch[y][1], mid+1, r, k); 61 } 62 63 int getsum(int x, int y, int l, int r, int L, int R) 64 { 65 if(L > R) return 0; 66 if(l >= L && r <= R) return sum[y]-sum[x]; 67 int mid = (l+r)/2, res = 0; 68 if(L <= mid) res+=getsum(ch[x][0], ch[y][0], l, mid, L, R); 69 if(R > mid) res+=getsum(ch[x][1], ch[y][1], mid+1, r, L, R); 70 return res; 71 } 72 73 int main() 74 { 75 int i, j, x, L, R; 76 scanf("%d", &N); 77 for(int i = 1; i <= N; i++){ 78 scanf("%d", &a[i]); 79 d[i] = a[i]; 80 } 81 sort(d+1, d+1+N); 82 siz = unique(d+1, d+1+N)-d-1; 83 for(i = 1; i <= N; i++) 84 a[i] = lower_bound(d+1, d+1+siz, a[i])-d; 85 86 lim = sqrt(N); 87 for(i = 1; i <= N; i+=lim){ 88 bl[++cnt] = i;br[cnt] = min(N, i+lim-1); 89 for(j = bl[cnt]; j <= br[cnt]; j++) 90 pos[j] = cnt; 91 } 92 93 for(i = 1; i <= cnt; i++){ 94 add1(a[br[i]], 1); 95 for(j = br[i]-1; j >= 1; j--){ 96 f[j][i] = f[j+1][i]+query1(a[j]-1); 97 add1(a[j], 1); 98 } 99 for(j = br[i]; j >= 1; j--){ 100 add1(a[j], -1); 101 } 102 } 103 104 for(i = 1; i <= N; i++) 105 update(root[i-1], root[i], 1, N, a[i]); 106 107 108 scanf("%d", &M); 109 ans = 0; 110 while(M--){ 111 scanf("%d %d", &L, &R); 112 L^=ans;R^=ans; 113 ans = 0; 114 if(L > R) {puts("0"); continue;} 115 if(pos[L] == pos[R]){ 116 for(j = L; j <= R; j++){ 117 ans+=query2(a[j]+1); 118 add2(a[j], 1); 119 } 120 for(j = L; j <= R; j++) 121 add2(a[j], -1); 122 } 123 else{ 124 if(br[pos[R]] == R){ 125 ans = f[L][pos[R]]; 126 } 127 else{ 128 ans = f[L][pos[R]-1]; 129 x = br[pos[R]-1]; 130 if(x){ 131 for(j = x+1; j <= R; j++){ 132 ans+= getsum(root[L-1], root[x], 1, N, a[j]+1, N); 133 } 134 for(j = x+1; j <= R; j++){ 135 ans+=query2(a[j]+1); 136 add2(a[j],1); 137 } 138 for(j = x+1; j <= R; j++) 139 add2(a[j], -1); 140 } 141 } 142 } 143 printf("%d\n", ans); 144 } 145 return 0; 146 }