洛谷P3567[POI2014]KUR-Couriers(主席树+二分)

时间:2023-03-09 03:29:54
洛谷P3567[POI2014]KUR-Couriers(主席树+二分)

题意:给一个数列,每次询问一个区间内有没有一个数出现次数超过一半

题解:

最近比赛太多,都没时间切水题了,刚好日推了道主席树裸题,就写了一下

然后

WA80

WA80

WA0

WA90

WA80

??????

结果重新审题发现没有数据范围????

哦,原来是500000,我是真的菜

因为必须要一个数出现超过一半

所以这个数肯定会在左子树和右子树中总个数和较大的那个里。

显然这样二分找到树底复杂度是logn的

如果此时树底这个点的数值大于一半,那么就输出这个解,否则puts("0")

以及:不用离散化!!!

代码如下:

#include<bits/stdc++.h>
#define lson tr[now].l
#define rson tr[now].r
using namespace std; struct tree
{
int l,r,sum,val;
}tr[]; int rt[],a[],n,m,cnt;
map<int,int> mm; inline int push_up(int now)
{
tr[now].sum=tr[lson].sum+tr[rson].sum;
} int insert(int &now,int fa,int l,int r,int pos)
{
if(!now) now=++cnt;
if(l==r)
{
tr[now].sum=tr[fa].sum+;
tr[now].val=l;
return ;
}
register int mid=(l+r)>>;
if(pos<=mid)
{
insert(tr[now].l,tr[fa].l,l,mid,pos);
tr[now].r=tr[fa].r;
}
else
{
tr[now].l=tr[fa].l;
insert(tr[now].r,tr[fa].r,mid+,r,pos);
}
push_up(now);
} inline int query(int a,int b,int l,int r,int tar)
{
if(l==r)
{
if(tr[a].sum-tr[b].sum>=tar) return l;
else return ;
}
register int mid=(l+r)>>;
register int ls=tr[tr[a].l].sum-tr[tr[b].l].sum;
register int rs=tr[tr[a].r].sum-tr[tr[b].r].sum;
if(ls>rs) return query(tr[a].l,tr[b].l,l,mid,tar);
else return query(tr[a].r,tr[b].r,mid+,r,tar);
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)
{
scanf("%d",&a[i]);
insert(rt[i],rt[i-],,,a[i]);
}
int from,to;
while(m--)
{
scanf("%d%d",&from,&to);
register int mid=(to-from+)/+;
printf("%d\n",b[query(rt[to],rt[from-],,,mid)]);
}
}