Submit: 2210 Solved: 853
[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
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6
Sample Output
1
0
3
0
4
0
3
0
4
HINT
【数据范围】
n,m≤500000
2016.7.9重设空间,但未重测!
Source
思路
主席树+权值线段树
两颗树确定区间,然后树上跑二分。
代码实现
1 #include<cstdio> 2 const int maxn=5e5+10; 3 int n,m,s[maxn]; 4 int hd[maxn]; 5 int ps,t[maxn<<5],ls[maxn<<5],rs[maxn<<5]; 6 int a,b,c; 7 void add(int pre,int suc,int l,int r,int v){ 8 t[suc]=t[pre]+1; 9 if(l==r) return; 10 ls[suc]=ls[pre],rs[suc]=rs[pre]; 11 int mid=l+r>>1; 12 if(v<=mid) ls[suc]=++ps,add(ls[pre],ls[suc],l,mid,v); 13 else rs[suc]=++ps,add(rs[pre],rs[suc],mid+1,r,v); 14 } 15 int search(int pre,int suc,int l,int r,int v){ 16 while(l!=r){ 17 int mid=l+r>>1; 18 if(t[ls[suc]]-t[ls[pre]]>v) suc=ls[suc],pre=ls[pre],r=mid; 19 else if(t[rs[suc]]-t[rs[pre]]>v) suc=rs[suc],pre=rs[pre],l=mid+1; 20 else return 0; 21 } 22 return l; 23 } 24 int main(){ 25 scanf("%d%d",&n,&m); 26 for(int i=1;i<=n;i++){ 27 scanf("%d",&a); 28 hd[i]=++ps; 29 add(hd[i-1],hd[i],1,n,a); 30 } 31 for(int i=1;i<=m;i++){ 32 scanf("%d%d",&b,&c); 33 printf("%d ",search(hd[b-1],hd[c],1,n,c-b+1>>1)); 34 } 35 return 0; 36 }