BZOJ 2223: [Coci 2009]PATULJCI【主席树】

2223: [Coci 2009]PATULJCI

【题目描述】
传送门

【题解】

主席树的裸题,要找出现次数大于一半的,那么他肯定出现在当前的左子树或右子树中,就这样查找就可以了。

代码如下

#include<cstdio>
#include<cctype>
#include<algorithm>
#define MAXN 300005
using namespace std;
int n,m,K,A[MAXN],hsh[MAXN],T[MAXN];
int read(){
    int ret=0;char ch=getchar();bool f=1;
    for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
    for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-48;
    return f?ret:-ret;
}
struct ZXTree{
    int tot,L[MAXN<<5],R[MAXN<<5],Sum[MAXN<<5];
    int Build(int l,int r){
        int rt=++tot;Sum[rt]=0;
        if(l<r){
            int mid=(r+l)>>1;
            L[rt]=Build(l,mid);
            R[rt]=Build(mid+1,r);
        }
        return rt;
    }
    int Updata(int lst,int l,int r,int x){
        int rt=++tot;
        L[rt]=L[lst],R[rt]=R[lst],Sum[rt]=Sum[lst]+1;
        if(l<r){
            int mid=(r+l)>>1;
            if(x<=mid) L[rt]=Updata(L[lst],l,mid,x);
            else R[rt]=Updata(R[lst],mid+1,r,x);
        }
        return rt;
    }
    int Query(int u,int v,int l,int r,int p){
        if(l>=r) return l;
        int mid=(r+l)>>1,NowL=Sum[L[v]]-Sum[L[u]],NowR=Sum[R[v]]-Sum[R[u]];
        if(NowL>p) return Query(L[u],L[v],l,mid,p);
        if(NowR>p) return Query(R[u],R[v],mid+1,r,p);
        return 0;
    }
}Tre;
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    n=read(),K=read();
    for(int i=1;i<=n;i++) A[i]=read();
    T[0]=Tre.Build(1,K);
    for(int i=1;i<=n;i++) T[i]=Tre.Updata(T[i-1],1,K,A[i]);
    m=read();
    for(int i=1;i<=m;i++){
        int L=read(),R=read(),x=(R-L+1)>>1,Now=Tre.Query(T[L-1],T[R],1,K,x);
        if(Now==0) printf("no\n");else printf("yes %d\n",Now);
    }
    return 0;
}
posted @ 2018-05-25 21:35  XSamsara  阅读(105)  评论(0编辑  收藏  举报