您的位置:首页 > 其它

【bzoj3524】Couriers——主席树

2017-08-18 13:56 218 查看

Description

给一个长度为n的序列a。1≤a[i]≤n(n,m<=500000)。
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

 

 

 

其实这个直接套一下主席树就好了,只不过当二分到l==r时记得判断一下e[rr].sum-e[ll].sum是否大于(r-l+1)/2就好啦。

#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=5e5+5;
using namespace std;
struct point{
int rt,sum,ls,rs;
}e[N*20];
int a
,b
,tot=0,n,m,sz,x,y;
void build(int &rt,int le,int ri)
{
tot++;rt=tot;
e[rt].sum=0;
if(le==ri)return ;
int mid=(le+ri)>>1;
build(e[rt].ls,le,mid);
build(e[rt].rs,mid+1,ri);
}
void up(int &rt,int l,int r,int last,int p)
{
rt=++tot;
e[rt].ls=e[last].ls;e[rt].rs=e[last].rs;
e[rt].sum=e[last].sum+1;
if(l==r)return;
int mid=(l+r)>>1;
if(p<=mid)up(e[rt].ls,l,mid,e[last].ls,p);
else up(e[rt].rs,mid+1,r,e[last].rs,p);
}
int query(int ll,int rr,int l,int r,int p)
{
if(l==r){if(e[rr].sum-e[ll].sum>=p)return l;else return 0;}
int mid=(l+r)>>1;
int d=e[e[rr].ls].sum-e[e[ll].ls].sum;
if(d>=p)return query(e[ll].ls,e[rr].ls,l,mid,p);
else return query(e[ll].rs,e[rr].rs,mid+1,r,p);
}
void find()
{
int ll,rr;
scanf("%d %d",&ll,&rr);
int an=query(e[ll-1].rt,e[rr].rt,1,sz,(rr-ll+1)/2+1);
printf("%d\n",b[an]);
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+n+1);
sz=unique(b+1,b+n+1)-(b+1);
build(e[0].rt,1,sz);
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+sz,a[i])-b;
for(int i=1;i<=n;i++)up(e[i].rt,1,sz,e[i-1].rt,a[i]);
while(m--)find();
return 0;
}
bzoj3524

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: