zoukankan      html  css  js  c++  java
  • [CDQ分治][树状数组][树套树] Jzoj P3197 K大数查询

    Description

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

    Input


    在输入文件sequence.in 中,第一行两个数n,m。意义如题目描述。
    接下来m 行每行形如1 a b c 或者2 a b c 如题目描述。

    Output

    在输出文件sequence.out 中,对于每个询问回答k 大数是多少。
     

    Sample Input

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

    Sample Output

    1
    2
    1
     

    Data Constraint


    30%的数据n=m=1000
    100%的数据n,m≤50000,并且后7 个点的数据n,m 的范围从32000 到50000近似成等差数列递增。a≤b≤n,1 操作中|c|≤n,2 操作中|c|≤maxlongint
     

    Hint

    第一个操作后位置1 的数只有1,位置2 的数也只有1。第二个操作后位置1的数有1、2,位置2 的数也有1、2。第三次询问位置1 到位置1 第2 大的数是1。第四次询问位置1 到位置1 第1 大的数是2。第五次询问位置1 到位置2 第3大的数是1。

    题解

    • 题目简洁大方,好评!!!
    • 这种题一般都是用树套树来做滴,题目大意:要求支持区间修改,区间查询第K大
    • 考虑一下CDQ分治,先二分一个答案
    • 我们就对于一下当前这一段的处理序列中,先依次处理,碰到询问就考虑是否可行
    • 如果对于一个询问,发现当前的x之下查询的ans大于那个值,说明答案更小,所以要放到左边去递归处理
    • 但是同时记得,把询问的值减掉查询出的ans,表示这一段肯定比它大,先减掉
    • 至于查询的话,区间修改、区间查询,可以用树状数组就行了

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #define ll long long
     5 #define N 50010
     6 using namespace std;
     7 int n,m,ans[N];
     8 ll sz1[N],sz2[N];
     9 bool bz[N];
    10 struct edge{ int d,x,y,c,op; }a[N],P[N],Q[N];
    11 void add(int x,int y) { for (int r=x;x<=n;x+=x&-x) sz1[x]+=y,sz2[x]+=r*y; }
    12 ll query(int x)
    13 {
    14     ll r=0;
    15     for (int i=x;i;i-=i&-i) r+=(x+1)*sz1[i]-sz2[i];
    16     return r;
    17 }
    18 void cdq(int L,int R,int l,int r)
    19 {
    20     if (L>R||l>r) return;
    21     if (l==r) 
    22     {
    23         for (int i=L;i<=R;i++) ans[a[i].d]=l;
    24         return;
    25     }
    26     int mid=l+r+1>>1,num1=0,num2=0;ll x;
    27     for (int i=L;i<=R;i++)
    28         if (a[i].op==1)
    29         {
    30             if (a[i].c>=mid) add(a[i].x,1),add(a[i].y+1,-1),P[++num2]=a[i]; else Q[++num1]=a[i];
    31         }
    32         else
    33         {
    34             x=query(a[i].y)-query(a[i].x-1);
    35             if (x>=a[i].c) P[++num2]=a[i]; else a[i].c-=x,Q[++num1]=a[i];
    36         }
    37     for (int i=L;i<=R;i++) if (a[i].op==1&&a[i].c>=mid) add(a[i].x,-1),add(a[i].y+1,1);
    38     for (int i=1;i<=num1;i++) a[L+i-1]=Q[i];
    39     for (int i=1;i<=num2;i++) a[L+num1+i-1]=P[i];
    40     cdq(L,L+num1-1,l,mid-1),cdq(L+num1,R,mid,r);
    41 }
    42 int main()
    43 {
    44     scanf("%d%d",&n,&m);
    45     for (int i=1;i<=m;i++)
    46     {
    47         scanf("%d%d%d%d",&a[i].op,&a[i].x,&a[i].y,&a[i].c),a[i].d=i;
    48         if (a[i].op==2) bz[i]=1;
    49     }
    50     cdq(1,m,1,n);
    51     for (int i=1;i<=m;i++) if (bz[i]) printf("%d
    ",ans[i]);
    52 }
  • 相关阅读:
    科研道路上培养的7种能力
    (OK) network diagnose tools
    linux-bridge-ping-high-latency-ebtables.txt
    houshoul
    Android x86 Virtual box with Internet and connection to adb?
    linux內核調試kmsg,dmesg
    Android Logging System
    Linux 日志级别(loglevel)详解
    Linux之绝处逢生------SysRq
    /proc/sysrq-trigger详解
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10335863.html
Copyright © 2011-2022 走看看