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
  • 相关阅读:
    oracle的安装与plsql的环境配置
    Working with MSDTC
    soapui-java.lang.Exception Failed to load url
    Oracle 一个owner访问另一个owner的table,不加owner
    Call API relation to TLS 1.2
    Call API HTTP header Authorization: Basic
    VS2008 .csproj cannot be opened.The project type is not supported by this installat
    The changes couldn't be completed.Please reboot your computer and try again.
    Create DB Table View Procedure
    DB Change
  • 原文地址:https://www.cnblogs.com/hoskey/p/4339810.html
Copyright © 2011-2022 走看看