• 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
    ", ans);
    144     }
    145     return 0;
    146 }
    View Code
  • 相关阅读:
    python day05
    python day04
    python day03
    python day02
    计算机基本了解
    流程控制
    MFC程序中创建文件夹(文件路径)
    svn移动目录并且保存历史日志
    C++单例模式的问题
    PtInRect 的详细范围
  • 原文地址:https://www.cnblogs.com/ymzjj/p/10400863.html
Copyright © 2020-2023  润新知