zoukankan      html  css  js  c++  java
  • 整体二分初识--POJ2104:K-th Number

    n<=100000个数有m<=5000个询问,每次问区间第k大。

    方法一:主席树!……

    方法二:整体二分。

    整体二分一次性计算半个值域对一个区间的询问的贡献,然后根据“这半边的贡献在某个询问中可不可以直接处理掉”把询问分两部分,并按“数字的值是否在这半边”把数字也分成两部分,这样把一个区间和值域都分掉了,然后就可以在f(n)logMax的时间出解,其中f(n)表示计算一次这样的贡献需要的时间。

    在这题里,只需要看某个区间里在值域[L,mid]中出现的数字的个数有没有到K个,以此划分成两个区域。因此树状数组搞一搞,f(n)=nlogn,大功告成。

     1 //#include<iostream>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cstdio>
     5 //#include<bitset>
     6 #include<algorithm>
     7 //#include<cmath>
     8 using namespace std;
     9 
    10 int n,m;
    11 #define maxn 200011
    12 const int inf=0x3f3f3f3f;
    13 struct App
    14 {
    15     int x,y,z,id,type;
    16     //type=1 表示修改,其中x为位置,y为数值,z为在bit中的修改权值 
    17     //type=0 表示询问,其中x,y为左右端点,z是第几大,id询问编号 
    18 }a[maxn],al[maxn],ar[maxn];
    19 int ans[maxn];
    20 
    21 struct BIT
    22 {
    23     int a[maxn];
    24     void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;}
    25     int query(int x) {int ans=0; for (;x;x-=x&-x) ans+=a[x]; return ans;}
    26 }t;
    27 
    28 void solve(int L,int R,int ql,int qr)
    29 {
    30     if (ql>qr || L>R) return;
    31     if (L==R)
    32     {
    33         for (int i=ql;i<=qr;i++) ans[a[i].id]=L;
    34         return;
    35     }
    36     const int mid=(L+R)>>1;
    37     int lal=0,lar=0;
    38     for (int i=ql;i<=qr;i++)
    39     {
    40         if (a[i].type)
    41         {
    42             if (a[i].y<=mid)
    43             {
    44                 t.add(a[i].x,a[i].z);
    45                 al[++lal]=a[i];
    46             }
    47             else ar[++lar]=a[i];
    48         }
    49         else
    50         {
    51             int tmp=t.query(a[i].y)-t.query(a[i].x-1);
    52             if (tmp>=a[i].z) al[++lal]=a[i];
    53             else
    54             {
    55                 ar[++lar]=a[i];
    56                 ar[lar].z-=tmp;
    57             }
    58         }
    59     }
    60     for (int i=1;i<=lal;i++) if (al[i].type==1) t.add(al[i].x,-al[i].z);
    61     for (int i=1,j=ql;i<=lal;i++,j++) a[j]=al[i];
    62     for (int i=1,j=ql+lal;i<=lar;i++,j++) a[j]=ar[i];
    63     solve(L,mid,ql,ql+lal-1);
    64     solve(mid+1,R,ql+lal,qr);
    65 }
    66 
    67 int main()
    68 {
    69     scanf("%d%d",&n,&m);
    70     for (int i=1;i<=n;i++) scanf("%d",&a[i].y),a[i].x=i,a[i].z=1,a[i].type=1;
    71     for (int i=1,j=n+1;i<=m;i++,j++) scanf("%d%d%d",&a[j].x,&a[j].y,&a[j].z),a[j].id=i,a[j].type=0;
    72     solve(-inf,inf,1,n+m);
    73     for (int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    74     return 0;
    75 }
    View Code
  • 相关阅读:
    常量的三种定义方式和static在c语言中的三种修饰
    字符串的定义方式;输出和计算长度时的细节
    指针小白:修改*p与p会对相应的地址的变量产生什么影响?各个变量指针的长度为多少?
    习题 :任意输入十个数按大小排序;构造简单数学运算模块(形参和实参)
    for循环简单实例(打印乘法表,打印菱形)
    几个简单if程序的细节比较与加法程序设计
    冒泡排序法,两个数组内容的互换,两个变量之间的交换
    scanf加不加 ?
    jqplot导入包小结
    使用ajax与jqplot的小体会
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8203399.html
Copyright © 2011-2022 走看看