整体二分学习

意思能懂,解说也都懂,但是为什么这样(查询和修改都弄在一起就能......)还是有些疑问。觉得看到题目知道是整体二分也不好写。

带修改的区间第k小,经典代码。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define maxn 220000
#define inf 1000000000

using namespace std;
struct query
{
    int x,y,k,s,tp,cur;
} q[maxn],q1[maxn],q2[maxn];
int a[maxn],ans[maxn],tmp[maxn],t[maxn];
int n,m,num,cnt;

void add(int x,int y)
{
    for (int i=x; i<=n; i+=(i&-i)) t[i]+=y;
}

int ask(int x)
{
    int tmp=0;
    for (int i=x; i>0; i-=(i&-i)) tmp+=t[i];
    return tmp;
}

void divide(int head,int tail,int l,int r)
{
    //cout<<head<<' '<<tail<<' '<<l<<' '<<r<<endl;
    if (head>tail) return ;
    if (l==r)
    {
        for (int i=head; i<=tail; i++)
            if (q[i].tp==3) ans[q[i].s]=l;//,cout<<l<<endl;
        return ;
    }
    int mid=(l+r)>>1;
    for (int i=head; i<=tail; i++)//区间内小于mid的值的个数
    {
        if (q[i].tp==1&&q[i].y<=mid) add(q[i].x,1);
        else if (q[i].tp==2&&q[i].y<=mid) add(q[i].x,-1);
        else if (q[i].tp==3) tmp[i]=ask(q[i].y)-ask(q[i].x-1);
    }
    for (int i=head; i<=tail; i++)//还原
    {
        if (q[i].tp==1&&q[i].y<=mid) add(q[i].x,-1);
        else if (q[i].tp==2&&q[i].y<=mid) add(q[i].x,1);
    }
    
    
    int l1=0,l2=0;
    for (int i=head; i<=tail; i++)
    {
        if (q[i].tp==3)//查询
        {
            if (q[i].cur+tmp[i]>q[i].k-1)//q[i].cur+tmp[i]表示累积了多少个数(之前的+这次的),超限了,就不能加了
                q1[++l1]=q[i];
            else//加上这轮的,小于k的数还不够
            {
                q[i].cur+=tmp[i];//现在有多少小的了
                q2[++l2]=q[i];
            }
        }
        else
        {
            if (q[i].y<=mid) q1[++l1]=q[i];//不够进q1
            else q2[++l2]=q[i];
        }
    }
    for (int i=1; i<=l1; i++) q[head+i-1]=q1[i];
    for (int i=1; i<=l2; i++) q[head+l1+i-1]=q2[i];
    divide(head,head+l1-1,l,mid);
    divide(head+l1,tail,mid+1,r);
}

int main()
{
    //freopen("ranking.in","r",stdin);
    //freopen("ranking.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        q[++num].x=i;
        q[num].y=a[i];
        q[num].tp=1;
        q[num].s=0;
    }
    char sign;
    int x,y,z;
    for (int i=1; i<=m; i++)
    {
        scanf("\n%c",&sign);
        if (sign=='Q')
        {
            scanf("%d%d%d",&x,&y,&z);
            q[++num].x=x;
            q[num].y=y;
            q[num].k=z;
            q[num].tp=3;
            q[num].s=++cnt;
        }
        else
        {
            scanf("%d%d",&x,&y);
            q[++num].x=x;
            q[num].y=a[x];
            q[num].tp=2;
            q[num].s=0;

            q[++num].x=x;
            q[num].y=y;
            q[num].tp=1;
            q[num].s=0;

            a[x]=y;
        }
    }
    divide(1,num,0,inf);
    for (int i=1; i<=cnt; i++)
        printf("%d\n",ans[i]);
    return 0;
}

 

posted on 2016-09-14 20:38  very_czy  阅读(168)  评论(0编辑  收藏  举报

导航