zoukankan      html  css  js  c++  java
  • 【ZOJ2112】【整体二分+树状数组】带修改区间第k大

    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

    【分析】

    裸题,不说了。

    按照这种方法的话,离线的带插入修改区间第K大也应该可以做了。

    不过这题的经典作法是树状数组上套可持久化线段树,不过这样空间消耗会很大。

    可能要用动态开点?

    转一个用块状链表的:http://www.cnblogs.com/zhj5chengfeng/archive/2013/08/19/3268162.html

      1 /*
      2 宋代晏殊
      3 《蝶恋花·槛菊愁烟兰泣露》
      4 
      5 槛菊愁烟兰泣露。罗幕轻寒,燕子双飞去。明月不谙离恨苦。斜光到晓穿朱户。
      6 昨夜西风凋碧树。独上高楼,望尽天涯路。欲寄彩笺兼尺素。山长水阔知何处。
      7 */
      8 #include <iostream>
      9 #include <cstdio>
     10 #include <algorithm>
     11 #include <cstring>
     12 #include <vector>
     13 #include <utility>
     14 #include <iomanip>
     15 #include <string>
     16 #include <cmath>
     17 #include <queue>
     18 #include <assert.h>
     19 #include <map>
     20 #include <ctime>
     21 #include <cstdlib>
     22 #include <stack>
     23 #define LOCAL
     24 const int INF = 1000000000;
     25 const int MAXN = 300000 + 10;
     26 using namespace std;
     27 struct QUERY{
     28        int x, y;
     29        int k, s, type, cur;//cur用来记录前面的值 
     30 }q[MAXN], q1[MAXN], q2[MAXN];
     31 int Ans[MAXN];
     32 int tmp[MAXN], c[MAXN];
     33 int n, m, num, cnt;
     34 int data[MAXN];
     35 
     36 inline int lowbit(int x){return x&-x;}
     37 void add(int x, int val){
     38      while (x <= n){
     39            c[x] += val;
     40            x += lowbit(x);
     41      }
     42      return;
     43 }
     44 int sum(int x){
     45     int cnt = 0;
     46     while (x > 0){
     47           cnt += c[x];
     48           x -= lowbit(x);
     49     }
     50     return cnt;
     51 }
     52 //整体二分 
     53 void solve(int l, int r, int L, int R){
     54      //这两个都是结束条件
     55      if (l > r) return;
     56      if (L == R){//更新答案
     57         for (int i = l; i <= r; i++)
     58         if (q[i].type == 3) Ans[q[i].s] = L;
     59         return;
     60      }
     61      int mid = (L + R) >> 1;
     62      for (int i = l; i <= r; i++){
     63          if (q[i].type == 1 && q[i].y <= mid) add(q[i].x, 1);
     64          else if (q[i].type == 2 && q[i].y <= mid) add(q[i].x, -1);
     65          else if (q[i].type == 3) tmp[i] = sum(q[i].y) - sum(q[i].x - 1);
     66      }
     67      //更新完了就要清除标记了
     68      for (int i = l; i <= r; i++){
     69          if (q[i].type == 1 && q[i].y <= mid) add(q[i].x, -1);
     70          else if (q[i].type == 2 && q[i].y <= mid) add(q[i].x, 1);
     71      }
     72      int l1 = 0, l2 = 0;
     73      for (int i = l; i <= r; i++){
     74          if (q[i].type == 3){
     75             //不用id就直接改 
     76             if (q[i].cur + tmp[i] > q[i].k - 1) q1[++l1] = q[i];
     77             else {
     78                  q[i].cur += tmp[i];
     79                  q2[++l2] = q[i];
     80             }
     81          }else{
     82             if (q[i].y <= mid) q1[++l1] = q[i];
     83             else q2[++l2] = q[i];
     84          }        
     85      }
     86      for (int i = 1; i <= l1; i++) q[i + l - 1] = q1[i];
     87      for (int i = 1; i <= l2; i++) q[i + l1 + l - 1] = q2[i];
     88      solve(l, l + l1 - 1, L, mid);
     89      solve(l + l1, r, mid + 1, R);
     90 }
     91 void init(){
     92      memset(c, 0, sizeof(c));
     93      cnt = num = 0;//指针初始化,num记录总的操作数量 
     94      scanf("%d%d", &n, &m);
     95      for (int i = 1; i <= n; i++){
     96          num++;
     97          scanf("%d", &data[i]);
     98          q[num].x = i;q[num].type = 1;//1代表插入
     99          q[num].s = 0;q[num].y = data[i];//没有用y就当val用 
    100      } 
    101      for (int i = 1; i <= m; i++){
    102          char str[2];
    103          num++;
    104          scanf("%s", str);
    105          if (str[0] == 'Q'){
    106             int l, r, k;
    107             scanf("%d%d%d", &l, &r, &k);
    108             q[num].x = l;q[num].y = r;
    109             q[num].type = 3; q[num].s = ++cnt;
    110             q[num].k = k;
    111          }else{
    112             int l, x;
    113             scanf("%d%d", &l, &x);
    114             q[num].x = l;q[num].y = data[l];//2为删除 
    115             q[num].type = 2;q[num].s = 0;
    116             q[++num].x = l;
    117             q[num].y = x;//删除后插入 
    118             q[num].type = 1;
    119             q[num].s = 0;
    120             data[l] = x;//注意这里一定要改,不然会影响到后面的更新 
    121          }
    122      }
    123      for (int i = 1; i <= num; i++) q[i].cur = 0;
    124 }
    125 
    126 int main(){
    127     int T;
    128     
    129     scanf("%d", &T);
    130     while (T--){
    131           init();
    132           solve(1, num, 0, INF);
    133           for (int i = 1; i <= cnt; i++) printf("%d
    ", Ans[i]);
    134     }
    135     return 0;
    136 }
    View Code
  • 相关阅读:
    Orcad Pspice仿真
    AD导入Allegro brd文件(导入后找不到PCB的解决方法)
    VJTAG转VME DTB
    win10 非Unicode应用程序显示设置
    MFC多文档视图编程总结
    VC MFC开发示例下载
    FPGA仿真及时序约束分析
    VMWARE Thin APP
    VPX技术基础概论
    SecureCRT脚本(VBS)运行
  • 原文地址:https://www.cnblogs.com/hoskey/p/4339810.html
Copyright © 2011-2022 走看看