bzoj1901: Zju2112 Dynamic Rankings

本文介绍了一种结合整体二分和树状数组的数据结构算法,通过具体代码实现了解决复杂查询和更新操作的问题。文章详细展示了如何利用树状数组进行区间加法和前缀和查询,并结合整体二分技巧优化查询效率。

整体二分

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

int n,s[11000];
int lowbit(int x){return x&-x;}
void change(int x,int k)
{
    while(x<=n)
    {
        s[x]+=k;
        x+=lowbit(x);
    }
}
int getsum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=s[x];
        x-=lowbit(x);
    }
    return ret;
}

//------------bit----------------------

struct node
{
    int t,x,y,z;
}q[31000],lq[31000],rq[31000];int len;
int as[11000];
void solve(int l,int r,int st,int ed)
{
    if(st>ed)return ;
    if(l==r)
    {
        for(int i=st;i<=ed;i++)
            if(q[i].t>0)as[q[i].t]=l;
            return ;
    }
    
    int mid=(l+r)/2,lt=0,rt=0;
    for(int i=st;i<=ed;i++)
    {
        if(q[i].t==0)
        {
            if(q[i].y<=mid)
            {
                change(q[i].x,q[i].z);
                lq[++lt]=q[i];
            }
            else rq[++rt]=q[i];
        }
        else
        {
            int d=getsum(q[i].y)-getsum(q[i].x-1);
            if(d>=q[i].z)lq[++lt]=q[i];
            else 
            {
                q[i].z-=d;
                rq[++rt]=q[i];
            }
        }
    }
    
    for(int i=ed;i>=st;i--)
        if(q[i].t==0&&q[i].y<=mid)change(q[i].x,-q[i].z);
        
    for(int i=1;i<=lt;i++)q[st+i-1]=lq[i];
    for(int i=1;i<=rt;i++)q[st+lt+i-1]=rq[i];
    solve(l,mid,st,st+lt-1);
    solve(mid+1,r,st+lt,ed);
}

int a[11000];
char ss[10];
int main()
{
    int Q;
    scanf("%d%d",&n,&Q); len=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);len++;
        q[len].t=0,q[len].z=1;
        q[len].x=i,q[len].y=a[i];
    }
    int m=0,l,r,k;
    while(Q--)
    {
        scanf("%s",ss+1);
        if(ss[1]=='Q')
        {
            scanf("%d%d%d",&l,&r,&k);len++;
            q[len].t=++m,q[len].z=k;
            q[len].x=l,q[len].y=r;
        }
        else
        {
            scanf("%d%d",&l,&r);
            
            len++;
            q[len].t=0,q[len].z=-1;
            q[len].x=l,q[len].y=a[l];
            
            len++;
            q[len].t=0,q[len].z=1;
            q[len].x=l,q[len].y=r;
            a[l]=r;
        }
    }
    
    memset(s,0,sizeof(s));
    solve(0,1e9,1,len);
    for(int i=1;i<=m;i++)printf("%d\n",as[i]);
    return 0;
}

 

转载于:https://www.cnblogs.com/AKCqhzdy/p/9440677.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值