BZOJ 3524: [Poi2014]Couriers

题目大意:

给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。

题解:

如果这个数存在,那么这个数存在的区间中数的个数必定大于(r-l+1)/2,这里的区间以数值为下标。我们开一棵主席树然后在主席树上二分就可以找到这个数了。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<cstdio>
using namespace std;
int n,q,cnt,root[1000005],tree[10000005],ls[10000005],rs[10000005];
void insert(int &now,int pre,int l,int r,int x){
    now=++cnt;
    tree[now]=tree[pre]+1;
    if (l==r) return;
    int mid=(l+r)>>1;
    ls[now]=ls[pre],rs[now]=rs[pre];
    if (x<=mid) insert(ls[now],ls[pre],l,mid,x);
    else insert(rs[now],rs[pre],mid+1,r,x);
}
int query(int l,int r){
    int L=1,R=n,key=(r-l+1)>>1;
    int x=root[l-1],y=root[r];
    while (L<R){
        if (tree[y]-tree[x]<=key) return 0;
        int mid=(L+R)>>1;
        if (tree[ls[y]]-tree[ls[x]]>key){
            R=mid;
            x=ls[x];
            y=ls[y];
        }
        else {
            L=mid+1;
            x=rs[x];
            y=rs[y];
        }
    }
    if (tree[y]-tree[x]<=key) return 0;
    else return L;
}
int main(){
    scanf("%d%d",&n,&q);
    for (int i=1; i<=n; i++){
        int x;
        scanf("%d",&x);
        insert(root[i],root[i-1],1,n,x);
    }
    while (q--){
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",query(l,r));
    }
    return 0;
}

  

posted @   ~Silent  阅读(118)  评论(0编辑  收藏  举报
Live2D
欢迎阅读『BZOJ 3524: [Poi2014]Couriers』
点击右上角即可分享
微信分享提示