[POI2014]KUR-Couriers

这个题……一开始在挂……\(ORZ\)最终发现是我的主席树挂了……看来我该退役了\(OTZ\)

#\(\mathcal{\color{red}{Description}}\)

\(\color{cyan}{\mathcal{Link}}\)

给一个数列,每次询问一个区间内有没有一个数出现次数超过一半。如果有的话,输出这个数的数值。

#\(\mathcal{\color{red}{Solution}}\)

这个题好像可以上莫队……但是我校大佬讲莫队的时候没有用心听\(ORZ.\)

于是我们考虑用主席树\(qwq\) ,而在这里我们千万不要忘了主席树的最基本的功能是,维护一段区间内某个数字的个数

那我们就可以考虑,对于一个区间\(L\) ~ \(R\),我们取树\(R\)和树\(L - 1\)作差得到树\(W\),之后在\(W\)\(1\)~\(Len\)里面递归下去,递归的选择是某个区间的元素个数比区间内元素个数的二分之一要大。假设\(l\)区间内的元素数量比\((qr - ql + 1 )/2\)要大,那么首先对于区间\(r\)来说,\(r\)肯定不合法,所以向\(l\)区间继续递归下去。如果递归时出现左右区间都不满足,那么直接\(return\) \(0.\)

il int query(int Left, int Right, int l, int r, int k){
    if (l == r) return l ;
    int x = sum[L[Right]] - sum[L[Left]], y = sum[R[Right]] - sum[R[Left]] ;
    if ((x << 1) > k) return query(L[Left], L[Right], l, mid, k) ;
    if((y << 1) > k) return query(R[Left], R[Right], mid + 1, r, k) ;
    return 0 ;
}

嗯,其实只要明白了主席树的原理,这个题其实是很水的板子。不过像我这种蒟蒻因为入门的时候学的是区间第\(k\)小,所以忘记了主席树的基本功能……

#include<cstdio>
#include<iostream>
#include<algorithm>
#define il inline
#define MAXN 500510
#define mid ((l + r) >> 1)

using namespace std ;
int a, b, c ;
int pos, N, base[MAXN], aft[MAXN], M, i ;
int cnt, Len, T[MAXN << 5], L[MAXN << 5], R[MAXN << 5], sum[MAXN << 5] ;

il int qr(){
    int k = 0, f = 1; 
    char c = getchar() ;
    while(!isdigit(c)){
        if (c == '-') f = -1 ;
        c = getchar() ;
    }
    while(isdigit(c)){
        k = (k << 1) + (k << 3) + c - 48 ;
        c = getchar() ;
    } 
    return k * f;
}
il int build(int l, int r){
    int rt = ++ cnt ;
    sum[rt] = 0 ;
    if(l < r){
        L[rt] = build(l, mid) ;
        R[rt] = build(mid + 1, r) ;
    }
    return rt;
}
il int update(int last, int l, int r, int x){
    int rt = ++ cnt ;
    sum[rt] = sum[last] + 1 ;
    R[rt] = R[last] ;
    L[rt] = L[last] ;
    if (l < r){
        if (x <= mid) L[rt] = update(L[last], l, mid, x) ;
        else  R[rt] = update(R[last], mid + 1, r, x) ;
    }
    return rt ;
}
il int query(int Left, int Right, int l, int r, int k){
    if (l == r) return l ;
    int x = sum[L[Right]] - sum[L[Left]], y = sum[R[Right]] - sum[R[Left]] ;
    if ((x << 1) > k) return query(L[Left], L[Right], l, mid, k) ;
    if((y << 1) > k) return query(R[Left], R[Right], mid + 1, r, k) ;
    return 0 ;
}
int main(){
    cin >> N >> M;
    for(i = 1; i <= N; i ++){
        base[i] = qr() ;
        aft[i] = base[i] ;
    }
    sort(aft + 1, aft + N + 1) ;
    Len = unique(aft + 1, aft + N + 1) - (aft + 1) ; 
    T[0] = build(1, Len) ;
    for(i = 1; i <= N; i ++){
        pos = lower_bound(aft + 1, aft + Len + 1, base[i]) - aft;
        T[i] = update(T[i - 1], 1, Len, pos) ;
    }
    for(i = 1; i <= M; i ++){
        a = qr(), b = qr() ;
        printf("%d\n", query(T[a - 1], T[b], 1, Len, b - a + 1)) ;
    }
}

还有,千万不要写错变量啊!!比如\(Len\)\(N\)搞混了之类的\(QAQ\)

猜你喜欢

转载自www.cnblogs.com/pks-t/p/9235668.html