整体二分初识--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\n",ans[i]);
74     return 0;
75 }
View Code

 

posted @ 2018-01-05 11:28  Blue233333  阅读(188)  评论(0编辑  收藏  举报