题目描述
给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。
输入
第一行两个数n,m(n,m≤500000)。
第二行n个数,a[i]。
接下来m行,每行两个数l,r,表示询问[l,r]这个区间。
第二行n个数,a[i]。
接下来m行,每行两个数l,r,表示询问[l,r]这个区间。
输出
m行,每行对应一个答案。
样例输入
7 5
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6
样例输出
1
0
3
0
4
思路:建立可持久化权值线段树
AC代码:
#include <iostream> #include<cstdio> using namespace std; int x,n,m; int ls[10000010],rs[10000010],num[10000010],tot=0; int tree[500010]; inline void update(int pre,int& cur,int l,int r,int v){ cur=++tot; num[cur]=num[pre]+1; if(l==r) return; ls[cur]=ls[pre],rs[cur]=rs[pre]; int m=(l+r)>>1; if(v<=m) update(ls[pre],ls[cur],l,m,v); else update(rs[pre],rs[cur],m+1,r,v); } int ask(int ltree,int rtree,int k){ int l=1,r=n; while(l<r){ int m=(l+r)>>1; if(num[ls[rtree]]-num[ls[ltree]]>=k){ ltree=ls[ltree],rtree=ls[rtree]; r=m; } else if(num[rs[rtree]]-num[rs[ltree]]>=k){//区间内只可能有1个数出现次数超过一半 ltree=rs[ltree],rtree=rs[rtree]; l=m+1; } else return 0; } return l; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&x); update(tree[i-1],tree[i],1,n,x); } while(m--){ int l,r;scanf("%d%d",&l,&r); int ans=ask(tree[l-1],tree[r],(r-l+1)/2+1); printf("%d ",ans); } return 0; }