BZOJ-2223/3524: [Poi2014]Couriers

[文章目录]

Description

给一个长度为n的序列a。1≤a[i]≤n。m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。n,m≤500000

区间一个数出现次数大于(r-l+1)/2的数只能有一个(废话!!!)
所以说,如果一个区间存在合法解的话,所以,如果将权值按照区间划分的话,如果一个区间内的个数<(r-l+1)/2的话,这个区间就没有用了。
维护主席树,然后每次只会进入一个儿子,如果没有就直接跳出,直到找到一个儿子。
2534:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,c[501000],b[501000],w[501000],tot,cnt;
int getid(int x)
{
    int l=1,r=tot+1,mid;
    while(l<r)
    {
        mid=l+r>>1;
        if(x<=c[mid]) r=mid;
        else l=mid+1;
    }
    return r;
}
int root[501000];
struct seg
{
    int ls,rs,siz;
}t[10001000];
void update(int l,int r,int &x,int y,int z)
{
    x=++cnt; t[x].siz=t[y].siz+1;
    if(l==r) return ;
    int mid=l+r>>1;
    if(z<=mid) t[x].rs=t[y].rs,update(l,mid,t[x].ls,t[y].ls,z);
    else t[x].ls=t[y].ls,update(mid+1,r,t[x].rs,t[y].rs,z);
}
int query(int l,int r,int x,int y,int z)
{
    if(l==r) return l;
    if(t[t[y].ls].siz-t[t[x].ls].siz>z) return query(l,l+r>>1,t[x].ls,t[y].ls,z);
    if(t[t[y].rs].siz-t[t[x].rs].siz>z) return query((l+r>>1)+1,r,t[x].rs,t[y].rs,z);
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        scanf("%d",&w[i]),b[i]=w[i];
    sort(b+1,b+n+1); c[++tot]=b[1];
    for(int i=2;i<=n;++i) if(b[i]!=b[i-1]) c[++tot]=b[i];
    for(int i=1;i<=n;++i)
        update(1,tot,root[i],root[i-1],getid(w[i]));
    int x,y;
    while(m--)
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",c[query(1,tot,root[x-1],root[y],(y-x+1)/2)]);
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注