[BZOJ2223][Coci 2009]PATULJCI(整体二分+bit)

来源:互联网 发布:魔兽世界tbc数据库 编辑:程序博客网 时间:2024/06/09 21:21

题目描述

传送门

题解

以前好像做过一样的题,可持久化权值线段树裸题对吧…
整体二分的话也不难想
首先需要找单调性,乍一看是没有单调性的
不过,如果当前二分的答案为mid,这个区间里所有小于等于mid的数都不够的话,mid就一定变大,反之相反
那么每一次就把小于等于mid的数都加到bit里,然后判断二分的方向就可以了
需要注意的一点是,最后当l=r时就不能再加小于等于mid的数了,必须要加入严格等于mid的数,这样才能判断是否有解

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 300005int n,lim,m;struct hp{int val,loc,l,r,goal,id,num;}ins[N],q[N];int C[N],ans[N];int read(){    int x=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x;}void add(int loc,int val){    for (int i=loc;i<=n;i+=i&(-i))        C[i]+=val;}int query(int loc){    int ans=0;    for (int i=loc;i>=1;i-=i&(-i))        ans+=C[i];    return ans;}int cmpq(hp a,hp b){    return a.num<b.num;}void dvd(int l,int r,int x,int y,int a,int b){    if (a>b) return;    if (l==r)    {        for (int i=x;i<=y;++i)            if (ins[i].val==l) add(ins[i].loc,1);        for (int i=a;i<=b;++i)        {            int t=query(q[i].r)-query(q[i].l-1);            if (t>=(q[i].r-q[i].l+1)/2+1) ans[q[i].id]=l;            else ans[q[i].id]=-1;        }        for (int i=x;i<=y;++i)            if (ins[i].val==l) add(ins[i].loc,-1);        return;    }    int mid=(l+r)>>1;    int pmid=0,pa=0,pb=b-a+1;    for (int i=x;i<=y;++i)        if (ins[i].val<=mid)        {            pmid=i;            add(ins[i].loc,1);        }        else break;    for (int i=a;i<=b;++i)    {        int t=query(q[i].r)-query(q[i].l-1);        if (t>=q[i].goal) q[i].num=++pa;        else q[i].goal-=t,q[i].num=++pb;    }    for (int i=x;i<=pmid;++i)        add(ins[i].loc,-1);    sort(q+a,q+b+1,cmpq);    dvd(l,mid,x,pmid,a,a+pa-1);    dvd(mid+1,r,pmid+1,y,a+pa,b);}int cmpins(hp a,hp b){    return a.val<b.val;}int main(){    n=read();lim=read();    for (int i=1;i<=n;++i)    {        ins[i].val=read();        ins[i].loc=i;    }    sort(ins+1,ins+n+1,cmpins);    m=read();    for (int i=1;i<=m;++i)    {        q[i].l=read();q[i].r=read();        q[i].id=i;q[i].goal=(q[i].r-q[i].l+1)/2+1;    }    dvd(1,lim,1,n,1,m);    for (int i=1;i<=m;++i)        if (ans[i]==-1) puts("no");        else printf("yes %d\n",ans[i]);}
0 0