• K大数查询 BZOJ 3110


    K大数查询

    【问题描述】

    有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

    【输入格式】

    第一行N,M

    接下来M行,每行形如1 a b c或2 a b c

    【输出格式】

    输出每个询问的结果

    【样例输入】

    2 5
    1 1 2 1
    1 1 2 2
    2 1 1 2
    2 1 1 1
    2 1 2 3

    【样例输出】

    1
    2
    1

    【样例说明】

    第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。

    第二个操作 后位置 1的数有 1 、 2 ,位置 2 的数也有 1 、 2 。

    第三次询问 位置 1 到位置 1 第 2 大的数 是1 。

    第四次询问 位置 1 到位置 1 第 1 大的数是 2 。

    第五次询问 位置 1 到位置 2 第 3大的数是 1 。‍

    【数据范围】

    N,M<=50000,N,M<=50000,a<=b<=N

    1操作中abs(c)<=N,2操作中c<=Maxlongint


    题解:

    我们将询问离线,做整体二分

    题目中有负数,那么我们转化一下,将每个数变为n-i+1,输出答案时再变为n-ans+1

    对于一个操作1,如果这个操作加入的c是不超过mid的

    用线段树在区间内加1,表示此区间小于等于mid的数多了一个,那么将它放置到左区间

    否则将其放置到右区间,表示这个操作的贡献在右区间

    对于一个操作2,查询在区间内小于等于mid的数的个数tot

    如果tot超过k,将其放置到左区间,表示答案在左区间

    否则将k减去tot,放置到右区间,表示需要在右区间找k-tot大的数

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<cstdio>
      6 #include<cmath>
      7 using namespace std;
      8 struct S { long long x, y, z, id, flag; } a[1000001], c[1000001];
      9 bool lr[1000001];
     10 long long n, m, tot, maxx = -2147483647;
     11 long long sum[1000001], ans[1000001], node[1000001];
     12 void Down(long long k, int l, int r)
     13 {
     14     if(node[k] != 0)
     15     {
     16         int mi = (l + r) >> 1;
     17         node[k * 2] += node[k];
     18         node[k * 2 + 1] += node[k];
     19         sum[k * 2] += node[k] * (mi - l + 1);
     20         sum[k * 2 + 1] += node[k] * (r - mi);
     21         node[k] = 0;
     22     }
     23 }
     24 void Inc(int k, int l, int r, int x, int y, int z)
     25 {
     26     if(x <= l && r <= y)
     27     {
     28         sum[k] += z * (r - l + 1);
     29         node[k] += z;
     30         return;
     31     }
     32     Down(k, l, r);
     33     int mi = (l + r) >> 1;
     34     if(mi >= x) Inc(k * 2, l, mi, x, y, z);
     35     if(mi < y) Inc(k * 2 + 1, mi + 1, r, x, y, z);
     36     sum[k] = sum[k * 2] + sum[k * 2 + 1];
     37 }
     38 long long Sum(long long k, long long l, long long r, long long x, long long y)
     39 {
     40     if(x <= l && r <= y) return sum[k];
     41     Down(k, l, r);
     42     long long mi = (l + r) >> 1, res = 0;
     43     if(mi >= x) res += Sum(k * 2, l, mi, x, y);
     44     if(mi < y) res += Sum(k * 2 + 1, mi + 1, r, x, y);
     45     return res;
     46 }
     47 void Two(long long x, long long y, long long l, long long r)
     48 {
     49     cout<<x<<' '<<y<<' '<<l<<' '<<r<<endl;
     50     long long mi = (l + r) >> 1;
     51     if(l == r)
     52     {
     53         for(int i = x; i <= y; ++i)
     54             if(a[i].flag)
     55                 ans[a[i].id] = mi;
     56         return;
     57     }
     58     long long temp, s = x;
     59     for(int i = x; i <= y; ++i)
     60     {
     61         if(a[i].flag)
     62         {
     63             temp = Sum(1, 1, 2 * n + 1, a[i].x, a[i].y);
     64             if(temp < a[i].z)
     65             {
     66                 a[i].z -= temp;
     67                 lr[i] = false;
     68             }
     69             else
     70             {
     71                 ++s;
     72                 lr[i] = true;
     73             }
     74         }
     75         else
     76         {
     77             if(a[i].z <= mi)
     78             {
     79                 Inc(1, 1, 2 * n + 1, a[i].x, a[i].y, 1);
     80                 ++s;
     81                 lr[i] = true;
     82             }
     83             else lr[i] = false;
     84         }
     85     }
     86     for(int i = x; i <= y; ++i)
     87         if(!a[i].flag && a[i].z <= mi)
     88             Inc(1, 1, 2 * n + 1, a[i].x, a[i].y, -1);
     89     long long o = x;
     90     for(int i = x; i <= y; ++i)
     91         if(lr[i]) c[o++] = a[i];
     92         else c[s++] = a[i];
     93     for(int i = x; i <= y; ++i) a[i] = c[i];
     94     Two(x, o - 1, l, mi), Two(o, y, mi + 1, r);
     95 } 
     96 int main()
     97 {
     98     scanf("%lld%lld", &n, &m);
     99     for(int i = 1; i <= m; ++i)
    100     {
    101         scanf("%lld%lld%lld%lld", &a[i].flag, &a[i].x, &a[i].y, &a[i].z);
    102         --a[i].flag;
    103         if(!a[i].flag)
    104         {
    105             a[i].z = n - a[i].z + 1;
    106             maxx = (a[i].z > maxx) ? a[i].z : maxx;
    107         }
    108         else a[i].id = ++tot;
    109     }
    110     Two(1, m, 1, maxx);
    111     for(int i = 1; i <= tot; ++i) printf("%lld
    ", n - ans[i] + 1);
    112 }
  • 相关阅读:
    Apache Commons IO之FileUtils的常用方法
    Java之字节数组和字符串的转换问题
    Java之高级IO,Properties
    Java之IO流(字节流,字符流)
    Java之File与递归
    Java之线程池和Lambda表达式
    java之初学线程
    Java之初学异常
    Java之使用链表实现队列
    请求参数的绑定
  • 原文地址:https://www.cnblogs.com/lytccc/p/6537444.html
Copyright © 2020-2023  润新知