传送门(权限)
题面
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));
}
}