zoukankan      html  css  js  c++  java
  • BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)

    3110 [Zjoi2013]K大数查询

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

    Input

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

    Output

    输出每个询问的结果

    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

    HINT



    【样例说明】

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

    N,M<=50000
    a<=b<=N
    1操作中abs(c)<=N
    2操作中c<=Maxlongint


    题解

      让我们来考虑神奇的分治算法。

      整体二分!!(当你会了)

      首先当你已经掌握了树状数组的区间加和区间询问(如果不会->点这里

      我们考虑二分答案。

      注意进行以下操作要严格按照输入时间先后顺序来。

      首先对于加进去的数字c,我们把他变成n-c+1,这样就把询问前k大变成了前k小。

      如果是修改操作,如果修改的值比当前的mid值小,就修改,并扔到左区间里面。否则扔到右边。

      如果是询问操作,如果在当前的状态下,该询问的区间内查询到的数的个数res比当前询问的c要大(或者相等),那么显然答案在左区间,把他扔到左边,否则把他的c减掉res再扔到右边去。

      然后递归分治两个区间就可以了。

      (本质是个二分答案的升级版)

      

    参考代码:

      1 /**************************************************************
      2     Problem: 3110
      3     User: SongHL
      4     Language: C++
      5     Result: Accepted
      6     Time:1880 ms
      7     Memory:3640 kb
      8 ****************************************************************/
      9  
     10 #include<bits/stdc++.h>
     11 using namespace std;
     12 #define lowbit(x) x&-x
     13 #define clr(a,b) memset(a,b,sizeof a) 
     14 typedef long long ll;
     15 const int maxn=50005;
     16 int n,m,id[maxn],templ[maxn],tempr[maxn];
     17 ll tree[2][maxn];
     18 inline int read()
     19 {
     20     int x=0,f=1;char ch=getchar();
     21     while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
     22     while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
     23     return x*f;
     24 }
     25 inline void add(int t,int x,int y)//单点加 
     26 {
     27     while(x<=n+1)
     28     {
     29         tree[t][x]+=y;
     30         x+=lowbit(x);
     31     }
     32 }
     33 inline void update(int l,int r,int val)//区间加 
     34 {
     35     add(0,l,val);add(1,l,l*val);
     36     add(0,r+1,-val);add(1,r+1,-val*(r+1));
     37 }
     38 inline ll Sum(int t,int x)//前缀和 
     39 {
     40     ll ans=0;
     41     while(x>0)
     42     {
     43         ans+=tree[t][x];
     44         x-=lowbit(x);
     45     }
     46     return ans;
     47 }
     48 inline ll query(int l,int r)//区间求和 
     49 {
     50     return Sum(0,r)*(r+1)-Sum(0,l)*l-Sum(1,r)+Sum(1,l);
     51 }
     52 struct Node{
     53     int type,l,r,x,ans;
     54     void Get()
     55     {
     56         type=read();l=read();r=read();x=read();
     57         if(type==1) x=n-x+1;
     58     }
     59 } a[maxn];
     60  
     61 inline void Solve(int lx,int rx,int l,int r)
     62 {
     63     if(l>r) return ;
     64     if(lx==rx)
     65     {
     66         for(int i=l;i<=r;++i) a[id[i]].ans=lx;
     67         return ;
     68     }
     69     int midx=lx+rx>>1;
     70     int L=0,R=0;
     71     for(int i=l;i<=r;++i)
     72     {
     73         if(a[id[i]].type==1)
     74         {
     75             if(a[id[i]].x<=midx) templ[++L]=id[i],update(a[id[i]].l,a[id[i]].r,1);
     76             else tempr[++R]=id[i];
     77         }
     78         else
     79         {
     80             ll res=query(a[id[i]].l,a[id[i]].r);
     81             if(res>=a[id[i]].x) templ[++L]=id[i];
     82             else tempr[++R]=id[i],a[id[i]].x-=res;
     83         }
     84     }
     85     for(int i=1;i<=L;++i)
     86     {
     87         if(a[templ[i]].type==1)
     88             update(a[templ[i]].l,a[templ[i]].r,-1); 
     89     }
     90      
     91     for(int i=l;i<=l+L-1;++i) id[i]=templ[i-(l-1)];
     92     for(int i=r-R+1;i<=r;++i) id[i]=tempr[i-(r-R)];
     93      
     94     Solve(lx,midx,l,l+L-1);
     95     Solve(midx+1,rx,r-R+1,r);   
     96 }
     97  
     98 int main()
     99 {
    100     n=read();m=read();
    101     for(int i=1;i<=m;++i) a[i].Get(),id[i]=i;
    102     clr(tree,0);
    103     Solve(1,2*n+1,1,m);
    104     for(int i=1;i<=m;++i)
    105         if(a[i].type==2) printf("%d
    ",n-a[i].ans+1);
    106     return 0;   
    107 } 
    View Code

      

  • 相关阅读:
    CF750D New Year and Fireworks
    raw,qcow2虚拟磁盘挂载
    虚拟机嵌套kvm/vmware
    CentOS Linux 7硬盘安装
    文本界面听歌神器--moc
    Ubuntu14.04升级内核3.14.25
    (转)MySQL初识-架构-安装-初始化-连接-管理工具-数据文件
    Ubuntu14.04使用国内163源或sohu源
    虚拟磁盘格式转换(raw,qcow2,vmdk等)--qemu-img
    phpMyAdmin4.2.12安装配置
  • 原文地址:https://www.cnblogs.com/csushl/p/9941252.html
Copyright © 2011-2022 走看看