【BZOJ3524】Couriers,第一次的主席树

传送门(权限)
题面
3524: [Poi2014]Couriers

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 1449 Solved: 508
[Submit][Status][Discuss]
Description

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

Input

第一行两个数n,m。
第二行n个数,a[i]。
接下来m行,每行两个数l,r,表示询问[l,r]这个区间。

Output

m行,每行对应一个答案。

Sample Input

7 5

1 1 3 2 3 4 3

1 3

1 4

3 7

1 7

6 6

Sample Output

1

0

3

0

4

HINT

【数据范围】

n,m≤500000

写在前面:千里之行始于足下
思路:板子题,感谢Yveh的无私帮助!
注意:主席树要小心M啊!
代码:

#include<bits/stdc++.h>
#define M 500000
using namespace std;
int n,m,tot,cnt=1;
int data[M+10],root[M+10];
struct Chairman_tree
{
    int ch[2],siz;
}a[M*20];
void build(int now,int L,int R,int rt,int val)
{
    a[rt].siz=a[now].siz+1;
    if (L==R) return;
    int mid=(L+R)>>1;
    if (val<=mid)
        a[rt].ch[1]=a[now].ch[1],
        a[rt].ch[0]=++tot,
        build(a[now].ch[0],L,mid,a[rt].ch[0],val);
    else
        a[rt].ch[0]=a[now].ch[0],
        a[rt].ch[1]=++tot,
        build(a[now].ch[1],mid+1,R,a[rt].ch[1],val);
}
int get(int begin,int end,int L,int R,int k,int len)
{
    if (begin==end)
        if (a[R].siz-a[L].siz>len) return end;
        else return 0;
    int mid=(begin+end)>>1,t=a[a[R].ch[0]].siz-a[a[L].ch[0]].siz;
    if (t>=k)
        return get(begin,mid,a[L].ch[0],a[R].ch[0],k,len);
    else
        return get(mid+1,end,a[L].ch[1],a[R].ch[1],k-t,len);
}
main()
{
    scanf("%d%d",&n,&m);
    for (int i=0;i<=n;i++) root[i]=++tot;
    for (int i=1;i<=n;i++)
    {
        scanf("%d",data+i);
        build(root[i-1],1,n,root[i],data[i]);
    }
    int x,y;
    while (m--)
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",get(1,n,root[x-1],root[y],(y-x+1>>1)+1,y-x+1>>1));
    }
}

你可能感兴趣的:(【BZOJ3524】Couriers,第一次的主席树)