LuoguP3567 [POI2014]KUR-Couriers

菜死了,竟然没看出来这是一道主席树的模板题.还自己瞎YY了写奇技淫巧。
首先\([l,r]\)这个区间的主席树我们是很好求的。
如果一个数出现的次数严格大于\((r - l + 1) / 2\)
那么,第\((r - l + 1) /2\)大的数肯定是他,
但是,怎么判断第\((r - l + 1)/2\)大的数到底出现没出现更多次,好像没有思路。
但是,在递归查询第\(k\)大的时候,查询的排名不随区间改变而改变就好了
煮个栗子
普通的主席树如果左儿子(默认使用当前区间的主席树)有\(k - 1\)个数
我们将问题转化为查询右儿子第一大
但是这道题去查询右儿子第\(k\)大,如果右儿子也不足\(k\),说明没有数出现了\((r - l + 1) /2\)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cctype>
using namespace std;
const int N = 5e5 + 3;
struct node{
    int sum;
    int lc,rc;  
}a[N * 30];
int v[N],b[N],rt[N];
int n,m,t;
inline int read(){
    int v = 0,c = 1;char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') c = -1;
        ch = getchar(); 
    }
    while(isdigit(ch)){
        v = v * 10 + ch - 48;
        ch = getchar(); 
    }
    return v * c;   
}
inline void ins(int &u,int l,int r,int x){
    a[++t] = a[u];
    u = t;
    if(l == r){
        a[u].sum ++;
        return ;
    }
    int mid = (l + r) >> 1;
    if(x <= mid) ins(a[u].lc,l,mid,x);
    else ins(a[u].rc,mid + 1,r,x);
    a[u].sum = a[a[u].lc].sum + a[a[u].rc].sum;
}
inline int query(int u1,int u2,int l,int r,int x){
    if(l == r) return l;
    int s1 = a[a[u2].lc].sum - a[a[u1].lc].sum,s2 = a[a[u2].rc].sum - a[a[u1].rc].sum;
//  printf("%d %d\n",s1,s2);
    int mid = (l + r) >> 1;
    if(s1 > x) return query(a[u1].lc,a[u2].lc,l,mid,x);
    else if(s2 > x) return query(a[u1].rc,a[u2].rc,mid + 1,r,x);
    else return 0;  
}
int main(){
    n = read(),m = read();
    for(int i = 1;i <= n;++i) v[i] = b[i] = read();
    sort(b + 1,b + n + 1);
    b[0] = unique(b + 1,b + n + 1) - b - 1;
    for(int i = 1;i <= n;++i){
        rt[i] = rt[i - 1];
        v[i] = lower_bound(b + 1,b + b[0] + 1,v[i]) - b;
        ins(rt[i],1,b[0],v[i]);
    }
    while(m--){
        int l = read(),r = read();
        int k = (r - l + 1) / 2;
        int ans = query(rt[l - 1],rt[r],1,b[0],k);
        printf("%d\n",ans == 0 ? ans : b[ans]); 
    }
    return 0;   
}