BZOJ3524 [Poi2014]Couriers 主席树(模板)

给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。
显然出现次数超过一半的数最多只有1个
建出主席树,在树上二分查找即可

/**************************************************************
    Problem: 3524
    User: bdzxt
    Language: C++
    Result: Accepted
    Time:4160 ms
    Memory:124340 kb
****************************************************************/

#include<bits/stdc++.h>
#define LL long long 
#define clr(x,i) memset(x,i,sizeof(x))
using namespace std;
const int N=500005;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Node{
    int l,r,sum;
}t[N*20];
int n,m,cnt,a[N],rk[N],sz;
int rt[N];
void upd(int l,int r,int &x,int y,int pos)
{
    t[++cnt]=t[y];t[cnt].sum++;x=cnt;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)
      upd(l,mid,t[x].l,t[y].l,pos);
    else
      upd(mid+1,r,t[x].r,t[y].r,pos);
}
int query(int l,int r,int x,int y,int K)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(t[t[y].l].sum-t[t[x].l].sum>K)
      return query(l,mid,t[x].l,t[y].l,K);
    else if(t[t[y].r].sum-t[t[x].r].sum>K)
      return query(mid+1,r,t[x].r,t[y].r,K);
    else return 0;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) a[i]=rk[i]=read();
    sort(rk+1,rk+n+1);
    sz=unique(rk+1,rk+n+1)-rk-1;
    for(int i=1;i<=n;i++)
    {
        int v=lower_bound(rk+1,rk+sz+1,a[i])-rk;
        upd(1,sz,rt[i],rt[i-1],v);
    }
    while(m--)
    {
        int x=read(),y=read();
        int ret=query(1,sz,rt[x-1],rt[y],(y-x+1)/2);
        if(!ret)printf("0\n");
        else printf("%d\n",rk[ret]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wolf_reiser/article/details/79466810
今日推荐