首页 > 代码库 > Bzoj3524 [Poi2014]Couriers
Bzoj3524 [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
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
可持久化线段树。将数列从1到n位置依次加入可持久化线段树中,并将插入顺序作为时间顺序。
询问[L,R]区间中出现的数,可以利用时间R时的状态减去L-1时的状态,得到[L,R]区间内的数的数量,然后二分找出目标数即可。
/*by SilverN*/#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>#include<cmath>using namespace std;const int mxn=500010;int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f;}int n,m;struct node{ int lc,rc; int sum;}t[mxn*20];int root[mxn];int nct=0;void update(int la,int v,int l,int r,int &rt){ rt=++nct; t[rt]=t[la]; t[rt].sum++; if(l==r)return; int mid=(l+r)>>1; if(v<=mid)update(t[la].lc,v,l,mid,t[rt].lc); else update(t[la].rc,v,mid+1,r,t[rt].rc); return;}int query(int L,int R){ int l=1,r=n; int mid,la=root[L-1],y=root[R],tmp=(R-L+1)/2; while(l!=r){ if(t[y].sum-t[la].sum<=tmp)return 0; mid=(l+r)>>1; if(t[t[y].lc].sum-t[t[la].lc].sum>tmp){ r=mid; la=t[la].lc; y=t[y].lc; } else if(t[t[y].rc].sum-t[t[la].rc].sum>tmp){ //else:不可能两边次数都多于(R-L+1)/2 所以可以二分 l=mid+1; la=t[la].rc; y=t[y].rc; } else return 0; } return l;}int main(){ n=read();m=read(); int i,j,x,y,l,r; for(i=1;i<=n;i++){ x=read(); update(root[i-1],x,1,n,root[i]); } for(i=1;i<=m;i++){ x=read();y=read(); printf("%d\n",query(x,y)); } return 0;}
Bzoj3524 [Poi2014]Couriers
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。