「BZOJ3524 / 2223」[POI2014] Couriers
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
解析:
主席树板题。
代码:
#include <bits/stdc++.h>
using namespace std;
const int Max=500005;
int n,m,tot;
int tree[Max*20],root[Max*20],lc[Max*20],rc[Max*20];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void print(int x)
{
if(x>9) print(x/10);
putchar('0'+x%10);
}
inline void add(int fa,int &now,int l,int r,int x)
{
now=++tot,tree[now]=tree[fa]+1,lc[now]=lc[fa],rc[now]=rc[fa];
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) add(lc[fa],lc[now],l,mid,x);
else add(rc[fa],rc[now],mid+1,r,x);
}
inline int Q(int root1,int root2,int l,int r,int x)
{
if(l==r) return l;
int mid=(l+r)>>1;
if(tree[lc[root1]]-tree[lc[root2]]>x) return Q(lc[root1],lc[root2],l,mid,x);
else if(tree[rc[root1]]-tree[rc[root2]]>x) return Q(rc[root1],rc[root2],mid+1,r,x);
else return 0;
}
int main()
{
n=get_int(),m=get_int();
for(int i=1;i<=n;i++)
{
int x=get_int();
add(root[i-1],root[i],0,n,x);
}
while(m--)
{
int l=get_int(),r=get_int();
print(Q(root[r],root[l-1],0,n,(r-l+1)/2)),putchar('\n');
}
return 0;
}