2017 暑假艾教集训 day10 (补zoj2112带修改的第k大)整体二分


ZOJ   2112

带修改的区间第k小只用比静态的多加一个删除操作即可

#include <bits/stdc++.h>
using namespace std;
const int inf=1e9+7;
const int maxn=220000;
struct node
{
    int l,r,k,val,cur;
    int id,kind;
}q[maxn],q1[maxn],q2[maxn];
int bit[maxn];
int ans[maxn];
int book[maxn];
int n,m,a[maxn];

int lowbit(int x)
{
    return x&(-x);
}
void updata(int pos,int val)
{
    for(int i=pos;i<=n;i+=lowbit(i))
    {
        bit[i] += val;
    }
}
int query(int pos)
{
    int ans=0;
    for(int i=pos;i>0;i-=lowbit(i))
    {
        ans+=bit[i];
    }
    return ans;
}
void cdq(int begin,int end,int l,int r)
{
    if(begin > end) return;
    if(l==r)
    {
        for(int i=begin;i<=end;++i)
        {
            if(q[i].kind==3) ans[q[i].id] = l;
        }
        return;
    }
    int mid=(l+r)>>1;
    for(int i=begin;i<=end;++i)
    {
        if(q[i].kind==1 && q[i].val <= mid) updata(q[i].id,1);
        else if(q[i].kind==2 && q[i].val <=mid) updata(q[i].id,-1);
        else book[i] = query(q[i].r)-query( q[i].l -1);
    }
    for(int i=begin;i<=end;++i)
    {
        if(q[i].kind==1 && q[i].val <=mid) updata(q[i].id,-1);
        else if(q[i].kind==2 && q[i].val<=mid) updata(q[i].id,1);
    }
    int num1=0 , num2=0 ;
    for(int i=begin;i<=end;++i)
    {
        if(q[i].kind==3)
        {
            if(q[i].cur+book[i]>q[i].k-1)
            {
                q1[++num1] = q[i];
            }
            else
            {
                q[i].cur+=book[i];
                q2[++num2] = q[i];
            }
        }
        else
        {
            if(q[i].val<=mid) q1[++num1]=q[i];
            else q2[++num2] = q[i];
        }
    }
    for(int i=1;i<=num1;++i) q[begin+i-1] = q1[i];
    for(int i=1;i<=num2;++i) q[begin+num1+i-1] = q2[i];
    cdq(begin,begin+num1-1, l,mid);
    cdq(begin+num1 ,end, mid+1,r);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(bit,0,sizeof(bit));
        memset(book,0,sizeof(book));
        memset(a,0,sizeof(a));
        memset(q,0,sizeof(q));
        scanf("%d%d",&n,&m);
        int tot=0;
        int cnt=0;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
            q[++tot].cur=0; q[tot].id=i; q[tot].kind=1;
            q[tot].val=a[i];
        }
        char s[50];
        int x=0,y=0;
        for(int i=1;i<=m;++i)
        {
            scanf("%s",s);
            if(s[0]=='Q')
            {
                q[++tot].kind=3; q[tot].id=(++cnt); q[tot].val=0; q[tot].cur=0;
                scanf("%d%d%d",&q[tot].l,&q[tot].r,&q[tot].k);
            }
            else
            {
                scanf("%d%d",&x,&y);
                q[++tot].kind = 2; q[tot].id = x; q[tot].val=a[x];  q[tot].cur=0;
                q[++tot].kind = 1; q[tot].id = x; q[tot].val=y;  q[tot].cur=0;
                a[x]=y;
            }
        }
        cdq(1,tot,0,inf);
        for(int i=1;i<=cnt;++i)
        {
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值