[POI2014]KUR-Couriers

题意

给一个数列,每次询问一个区间内有没有一个数出现次数超过一半

题解

主席树,一个数出现次数>一半,这个区间内只有这一个数满足,那么主席树直接维护所有数的出现次数,直接在树上二分查询

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(500010), __(1e7);

IL ll Read(){
    RG char c = getchar(); RG ll x = 0, z = 1;
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, m, p[_], id[_], len, rt[__], ls[__], rs[__], sz[__], cnt;

IL void Build(RG int &x, RG int l, RG int r){
    x = ++cnt;
    if(l == r) return;
    RG int mid = (l + r) >> 1;
    Build(ls[x], l, mid); Build(rs[x], mid + 1, r);
}

IL void Modify(RG int &x, RG int l, RG int r, RG int pos){
    sz[++cnt] = sz[x]; ls[cnt] = ls[x]; rs[cnt] = rs[x]; sz[x = cnt]++;
    if(l == r) return;
    RG int mid = (l + r) >> 1;
    if(pos <= mid)Modify(ls[x], l, mid, pos);
    else Modify(rs[x], mid + 1, r, pos);
}

IL int Query(RG int A, RG int B, RG int l, RG int r, RG int half){
    if(l == r) return l;
    RG int sum1 = sz[ls[B]] - sz[ls[A]], sum2 = sz[rs[B]] - sz[rs[A]], mid = (l + r) >> 1;
    if(sum1 > half) return Query(ls[A], ls[B], l, mid, half);
    if(sum2 > half) return Query(rs[A], rs[B], mid + 1, r, half);
    return 0;
}

int main(RG int argc, RG char* argv[]){
    n = Read(); m = Read();
    for(RG int i = 1; i <= n; i++) id[i] = p[i] = Read();
    sort(p + 1, p + n + 1); len = unique(p + 1, p + n + 1) - p - 1;
    Build(rt[0], 1, len);
    for(RG int i = 1; i <= n; i++){
        id[i] = lower_bound(p + 1, p + len + 1, id[i]) - p;
        rt[i] = rt[i - 1];
        Modify(rt[i], 1, len, id[i]);
    }
    for(RG int i = 1, l, r; i <= m; i++)
        l = Read(), r = Read(), printf("%d\n", Query(rt[l - 1], rt[r], 1, len, (r - l + 1) >> 1));
    return 0;
}
posted @ 2017-12-25 20:47  Cyhlnj  阅读(185)  评论(0编辑  收藏  举报