• Dynamic Rankings ZOJ


    The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.

    Your task is to write a program for this computer, which

    - Reads N numbers from the input (1 <= N <= 50,000)

    - Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.


    Input

    The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.

    The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format

    Q i j k or
    C i t

    It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.

    There're NO breakline between two continuous test cases.


    Output

    For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])

    There're NO breakline between two continuous test cases.


    Sample Input

    2
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3
    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3


    Sample Output

    3
    6
    3
    6

    参考了大佬的博客:https://www.cnblogs.com/Empress/p/4659824.html

    题意就是求区间内的第 k 小的数,但是会改变区间里的数。

    因为数很大,所以首先要把所有的 a[i] ,包括更新过程的 a[i],然后拿去离散化。

    对于求区间第 k 大,基本思想还是和静态区间求第 k 小一样,先求前缀和,然后相减。然后得到区间内的数量关系,就可以求区间内的第 k 小了。但是这里有更新操作,原本的求区间的 node[node[y].l].sum - node[node[x].l].sum 就不能直接用了。

    这里我们维护两颗完全不同的树,对一开始的数列用普通的主席树来维护,对于更新操作,用一个树状数组来维护,树状数组的每个节点都是一颗树,因为是单点更新,每棵树都只要更新 log(n) 个节点,用主席树来更新。(一个只维护初始的样子,一个只维护更新的样子

    然后这样的话,我们只需要想办法求出在 R 树和 L 树在某个区间上的左边部分的差值,在加上 node[node[y].l].sum - node[node[x].l].sum,就可以确定第 k 小在这个区间的左边还是右边。然后就可以开始用主席树的套路了。

    然后这里为了求 R 树和 L 树在某个区间内的差值,我们定义一个 use 表示树状数组的目前结点对应的树是哪一颗,use 的更新类似于主席树递归时候从x -> node[x].l 这样子的过程,都是为了把它往左整体往左更新。.......其实还是感觉很抽象的东西

      1 /*
      2           .
      3          ';;;;;.
      4         '!;;;;;;!;`
      5        '!;|&#@|;;;;!:
      6       `;;!&####@|;;;;!:
      7      .;;;!&@$$%|!;;;;;;!'.`:::::'.
      8      '!;;;;;;;;!$@###&|;;|%!;!$|;;;;|&&;.
      9      :!;;;;!$@&%|;;;;;;;;;|!::!!:::;!$%;!$%`    '!%&#########@$!:.
     10      ;!;;!!;;;;;|$$&@##$;;;::'''''::;;;;|&|%@$|;;;;;;;;;;;;;;;;!$;
     11      ;|;;;;;;;;;;;;;;;;;;!%@#####&!:::;!;;;;;;;;;;!&####@%!;;;;$%`
     12     `!!;;;;;;;;;;!|%%|!!;::;;|@##%|$|;;;;;;;;;;;;!|%$#####%;;;%&;
     13     :@###&!:;;!!||%%%%%|!;;;;;||;;;;||!$&&@@%;;;;;;;|$$##$;;;%@|
     14     ;|::;;;;;;;;;;;;|&&$|;;!$@&$!;;;;!;;;;;;;;;;;;;;;;!%|;;;%@%.
     15    `!!;;;;;;;!!!!;;;;;$@@@&&&&&@$!;!%|;;;;!||!;;;;;!|%%%!;;%@|.
     16 %&&$!;;;;;!;;;;;;;;;;;|$&&&&&&&&&@@%!%%;!||!;;;;;;;;;;;;;$##!
     17 !%;;;;;;!%!:;;;;;;;;;;!$&&&&&&&&&&@##&%|||;;;!!||!;;;;;;;$&:
     18 ':|@###%;:;;;;;;;;;;;;!%$&&&&&&@@$!;;;;;;;!!!;;;;;%&!;;|&%.
     19  !@|;;;;;;;;;;;;;;;;;;|%|$&&$%&&|;;;;;;;;;;;;!;;;;;!&@@&'
     20   .:%#&!;;;;;;;;;;;;;;!%|$$%%&@%;;;;;;;;;;;;;;;;;;;!&@:
     21   .%$;;;;;;;;;;;;;;;;;;|$$$$@&|;;;;;;;;;;;;;;;;;;;;%@%.
     22     !&!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;|@#;
     23      `%$!;;;;;;;;;;;$@|;;;;;;;;;;;;;;;;;;;;;;;;!%$@#@|.
     24        .|@%!;;;;;;;;;!$&%||;;;;;;;;;;;;;;;;;!%$$$$$@#|.
     25            ;&$!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%#####|.
     26            |##$|!;;;;;;::'':;;;;;;;;;;;;;!%$$$@#@;
     27           ;@&|;;;;;;;::'''''':;;;;;;;|$&@###@|`
     28         .%##@|;;;;:::''''''''''::;!%&##$'
     29       `$##@$$@@&|!!;;;:'''''::::;;;;;|&#%.
     30     ;&@##&$%!;;;;;;::''''''''::;!|%$@#@&@@:
     31      .%@&$$|;;;;;;;;;;:'''':''''::;;;%@#@@#%.
     32     :@##@###@$$$$$|;;:'''':;;!!;;;;;;!$#@@#$;`
     33      `%@$$|;;;;;;;;:'''''''::;;;;|%$$|!!&###&'
     34      |##&%!;;;;;::''''''''''''::;;;;;;;!$@&:`!'
     35     :;!@$|;;;;;;;::''''''''''':;;;;;;;;!%&@$:                 !@#$'
     36       |##@@&%;;;;;::''''''''':;;;;;;;!%&@#@$%:              '%%!%&;
     37       |&%!;;;;;;;%$!:''''''':|%!;;;;;;;;|&@%||`            '%$|!%&;
     38       |@%!;;!!;;;||;:'''''':;%$!;;;;!%%%&#&%$&:           .|%;:!&%`
     39       !@&%;;;;;;;||;;;:''::;;%$!;;;;;;;|&@%;!$;          `%&%!!$&:
     40       '$$|;!!!!;;||;;;;;;;;;;%%;;;;;;;|@@|!$##;         !$!;:!$&:
     41        |#&|;;;;;;!||;;;;;;;;!%|;;;;!$##$;;;;|%'      `%$|%%;|&$'
     42         |&%!;;;;;;|%;;;;;;;;$$;;;;;;|&&|!|%&&;  .:%&$!;;;:!$@!
     43         `%#&%!!;;;;||;;;;;!$&|;;;!%%%@&!;;;!!;;;|%!;;%@$!%@!
     44         !&!;;;;;;;;;||;;%&!;;;;;;;;;%@&!;;!&$;;;|&%;;;%@%`
     45        '%|;;;;;;;;!!|$|%&%;;;;;;;;;;|&#&|!!||!!|%$@@|'
     46        .!%%&%'`|$;       :|$#%|@#&;%#%.
     47 */
     48 #include <map>
     49 #include <set>
     50 #include <list>
     51 #include <ctime>
     52 #include <cmath>
     53 #include <stack>
     54 #include <queue>
     55 #include <string>
     56 #include <vector>
     57 #include <cstdio>
     58 #include <bitset>
     59 #include <cstdlib>
     60 #include <cstring>
     61 #include <iostream>
     62 #include <algorithm>
     63 #define  lowbit(x)  x & (-x)
     64 #define  mes(a, b)  memset(a, b, sizeof a)
     65 #define  fi         first
     66 #define  se         second
     67 #define  pii        pair<int, int>
     68 #define  INOPEN     freopen("in.txt", "r", stdin)
     69 #define  OUTOPEN    freopen("out.txt", "w", stdout)
     70 
     71 typedef unsigned long long int ull;
     72 typedef long long int ll;
     73 const int    maxn = 5e4 + 10;
     74 const int    maxm = 1e5 + 10;
     75 const ll     mod  = 1e9 + 7;
     76 const ll     INF  = 1e18 + 100;
     77 const int    inf  = 0x3f3f3f3f;
     78 const double pi   = acos(-1.0);
     79 const double eps  = 1e-8;
     80 using namespace std;
     81 
     82 int n, m;
     83 int cas, tol, T;
     84 struct Node{
     85     int l, r;
     86     int sum;
     87 } node[maxn * 40];
     88 struct Ask{
     89     int l, r, k;
     90     int id;
     91 } ask[maxn / 3];
     92 int a[maxn];
     93 int S[maxn];    //树状数组的根
     94 int rt[maxn];    //主席树的根
     95 int use[maxn];    //use表示树状数组的各个结点对应的树是哪一颗
     96 vector<int> vv;
     97 int L, R;
     98 
     99 int getid(int x) {
    100     return lower_bound(vv.begin(), vv.end(), x) - vv.begin() + 1;
    101 }
    102 
    103 void init() {
    104     tol = 0;
    105     mes(a, 0);
    106     mes(S, 0);
    107     mes(rt, 0);
    108     vv.clear();
    109     mes(use, 0);
    110     mes(ask, 0);
    111     mes(node, 0);
    112 }
    113 
    114 int Sum(int pos) {
    115 //  各颗树从 S[i] 走到了 used[i] 的位置,然后求左边部分的和
    116     int ans = 0;
    117     for(int i=pos; i; i-=lowbit(i))
    118         ans += node[node[use[i]].l].sum;
    119     return ans;
    120 }
    121 
    122 void update(int l, int r, int &x, int y, int pos, int val) {
    123     x = ++tol;
    124     node[tol] = node[y];
    125     node[tol].sum += val;
    126     if(l == r)    return ;
    127     int mid = (l + r) >> 1;
    128     if(pos <= mid)
    129         update(l, mid, node[x].l, node[y].l, pos, val);
    130     else
    131         update(mid+1, r, node[x].r, node[y].r, pos, val);
    132 }
    133 
    134 void add(int pos, int k, int v) {
    135     for(int i=pos; i<=n; i+=lowbit(i)) {
    136         update(1, vv.size(), S[i], S[i], k, v);
    137     }
    138 }
    139 
    140 int query(int l, int r, int x, int y, int k) {
    141     if(l == r)    return l;
    142     int mid = (l + r) >> 1;
    143     //注意树状数组是 L 和 R 
    144     //因为是找 L 和 R 树链上的到达 use 位置的值
    145     int tmp = Sum(R) - Sum(L) + node[node[y].l].sum - node[node[x].l].sum;
    146     if(k <= tmp) {
    147         //往现在到达的x,y位置的两棵树的左边查询
    148         //把 L 和 R 这路径上的所有树状数组都往左子树更新
    149         for(int i=L; i; i-=lowbit(i))    use[i] = node[use[i]].l;
    150         for(int i=R; i; i-=lowbit(i))    use[i] = node[use[i]].l;
    151         return query(l, mid, node[x].l, node[y].l, k);
    152     } else {
    153         //往现在到达的x,y位置的两棵树的右边查询
    154         //把 L 和 R 这路径上的所有树状数组都往右子树更新
    155         for(int i=L; i; i-=lowbit(i))    use[i] = node[use[i]].r;
    156         for(int i=R; i; i-=lowbit(i))    use[i] = node[use[i]].r;
    157         return query(mid+1, r, node[x].r, node[y].r, k-tmp);
    158     }
    159 }
    160 
    161 int main() {
    162     scanf("%d", &T);
    163     while(T--) {
    164         init();
    165         scanf("%d%d", &n, &m);
    166         for(int i=1; i<=n; i++) {
    167             scanf("%d", &a[i]);
    168             vv.push_back(a[i]);
    169         }
    170         for(int i=1; i<=m; i++) {
    171             char ss[5];
    172             scanf("%s", ss);
    173             if(ss[0] == 'Q') {
    174                 ask[i].id = 1;
    175                 scanf("%d%d%d", &ask[i].l, &ask[i].r, &ask[i].k);
    176             } else {
    177                 ask[i].id = 0;
    178                 scanf("%d%d", &ask[i].l, &ask[i].r);
    179                 vv.push_back(ask[i].r);
    180             }
    181         }
    182         sort(vv.begin(), vv.end());        //离散化一下
    183         vv.erase(unique(vv.begin(), vv.end()), vv.end());
    184         for(int i=1; i<=n; i++) {
    185             int id = getid(a[i]);        //第一颗树
    186             update(1, vv.size(), rt[i], rt[i-1], id, 1);
    187             //vv里面的数可能不止有 n 个,切记不可以用 n
    188         }
    189         for(int i=1; i<=m; i++) {
    190             if(ask[i].id) {
    191                 L = ask[i].l-1, R = ask[i].r;
    192                 //从 L 和 R 位置开始, use 表示的从 L, R 的S根开始
    193                 for(int j=L; j; j-=lowbit(j))    use[j] = S[j];
    194                 for(int j=R; j; j-=lowbit(j))    use[j] = S[j];
    195                 int pos = query(1, vv.size(), rt[L], rt[R], ask[i].k);
    196                 printf("%d
    ", vv[pos-1]);
    197             } else {                    //第二颗树
    198                 int id = getid(a[ask[i].l]);
    199                 add(ask[i].l, id, -1);    //先把之前的清除掉,在加现在的 
    200                 id = getid(ask[i].r);
    201                 add(ask[i].l, id, 1);
    202                 a[ask[i].l] = ask[i].r;
    203             }
    204         }
    205     }
    206     return 0;
    207 }
    View Code
  • 相关阅读:
    撒旦撒旦撒
    的释放的是分
    识别真假搜索引擎(搜索蜘蛛)方法(baidu,google,Msn,sogou,soso等)
    [转]Tesseract-OCR (Tesseract的OCR引擎最先由HP实验室于1985年开始研发)
    使用SQLMAP对网站和数据库进行SQL注入攻击
    Kali Linux 安装教程-转
    【教程】如何修改路由表?
    基于comet服务器推送技术(web实时聊天)
    Ghost硬盘对拷
    Web 通信 之 长连接、长轮询(long polling)
  • 原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/10129249.html
Copyright © 2020-2023  润新知