POJ2104 K-th Number(线段树,二分,vector)

题意

不带修改区间第k小。(n<=100000)

题解

建立线段数和vector数组(vector为当前区间排列之后的序列)(归并)

然后对于每一个询问二分答案。

问题就转化为区间有多少数小于等于二分值。

对于我们每一个遍历的区间(线段数的节点)。

若与询问区间不相交return0。

若完全包含于询问区间则在此区间的vector上二分查找有多少数小于二分值(因为已经排好序,所以很好做)

若有相交部分则继续遍历子树。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<vector>
 7 using namespace std;
 8 const int N=100010;
 9 vector<int> d[N*5];
10 struct tree{
11     int l,r;
12 }tr[N*8];
13 const int INF=1000000007;
14 int a[N*2];
15 int n,m;
16 void build(int l,int r,int now){
17     tr[now].l=l;tr[now].r=r;
18     if(l==r){
19         d[now].push_back(-INF);
20         d[now].push_back(a[l]);
21         return;
22     }
23     int mid=(l+r)>>1;
24     build(l,mid,now*2);
25     build(mid+1,r,now*2+1);
26     int size1=d[now*2].size()-1;
27     int size2=d[now*2+1].size()-1;
28     int i=1,j=1;
29     d[now].push_back(-INF);
30     while(i<=size1&&j<=size2){
31         if(d[now*2][i]>d[now*2+1][j])d[now].push_back(d[now*2+1][j++]);
32         else d[now].push_back(d[now*2][i++]);
33     }
34     while(i<=size1)d[now].push_back(d[now*2][i++]);
35     while(j<=size2)d[now].push_back(d[now*2+1][j++]);
36     return;
37 }
38 int getnum(int now,int K){
39     int x=1;int y=d[now].size()-1;
40     int tmp=0;
41     while(x<=y){
42         int mid=(x+y)>>1;
43     //    cout<<x<<" "<<y<<endl;
44         if(d[now][mid]<=K){
45             tmp=mid;
46             x=mid+1;
47         }
48         else y=mid-1;
49     }
50     return tmp;
51 }
52 int check(int l,int r,int now,int K){
53 //    cout<<l<<" "<<r<<endl;
54     if(tr[now].l>r||tr[now].r<l)return 0;
55     if(l<=tr[now].l&&tr[now].r<=r){
56     //    cout<<l<<" "<<r<<" "<<getnum(now,K)<<endl;
57         return getnum(now,K);
58     }
59     int mid=(tr[now].l+tr[now].r)>>1;
60     int tmp1=check(l,r,now*2,K);
61     int tmp2=check(l,r,now*2+1,K);
62     return tmp1+tmp2; 
63 }
64 int search(int l,int r,int k){
65     int tmp;
66     int x=-INF;
67     int y=INF;
68     while(x<=y){
69         int mid=(x+y)>>1;
70         int num=check(l,r,1,mid);
71     //    cout<<mid<<" "<<num<<endl;
72         if(num>=k){
73             tmp=mid;
74             y=mid-1;
75         }
76         else x=mid+1;
77     }
78     return tmp;
79 }
80 int main(){
81     scanf("%d%d",&n,&m);
82     for(int i=1;i<=n;i++){
83         scanf("%d",&a[i]);
84     }
85     build(1,n,1);
86     for(int i=1;i<=m;i++){
87         int l,r,k;
88         scanf("%d%d%d",&l,&r,&k);
89         int ans=search(l,r,k);
90         printf("%d\n",ans);
91     }
92     return 0;
93 }
View Code

猜你喜欢

转载自www.cnblogs.com/Xu-daxia/p/9392549.html