BZOJ 3744: Gty的妹子序列 【分块 + 树状数组 + 主席树】

任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3744

3744: Gty的妹子序列

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 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

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 }
View Code

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值