HDU 5412 CRB and Queries 求区间第k小 CDQ分治+整体二分

恩。。CDQ分治是个神奇的东西。。其思想基于分治。。可以实现大部分离线的带修改的询问

资料:http://www.cnblogs.com/zig-zag/archive/2013/04/18/3027707.html

//author: CHC
//First Edit Time:  2015-09-04 13:18
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=1e+5 + 1000;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
int C[MAXN],A[MAXN],n,q,ans[MAXN];
void Add(int x,int v){
    for(int i=x;i<=n;i+=i&-i)C[i]+=v;
}
int Sum(int x){
    int cnt=0;
    for(int i=x;i>0;i-=i&-i)cnt+=C[i];
    return cnt;
}
struct point {
    int x,y,k,kind,qpos,delta,cur;
    point(){}
    point(int _x,int _y,int _k,int _kind,int _qpos,int _delta,int _cur):x(_x),y(_y),k(_k),kind(_kind),qpos(_qpos),delta(_delta),cur(_cur){}
}cs[MAXN<<2],ql[MAXN<<2],qr[MAXN<<2];
int tmp[MAXN<<2];
void cdq(int L,int R,int l,int r){
    if(L>R)return ;
    //printf("L:%d R:%d\n",L,R);
    //printf("l:%d r:%d\n",l,r);
    //system("pause");
    if(l==r){
        for(int i=L;i<=R;i++)
            if(cs[i].kind==1)ans[cs[i].qpos]=l;
        //printf("l:%d\n",l);
        return;
    }
    int mid=(l+r)>>1;
    for(int i=L;i<=R;i++){
        if(cs[i].kind==0&&cs[i].y<=mid)Add(cs[i].x,cs[i].delta);
        else if(cs[i].kind==1)tmp[i]=Sum(cs[i].y)-Sum(cs[i].x-1);
    }
    for(int i=L;i<=R;i++)
        if(cs[i].kind==0&&cs[i].y<=mid)Add(cs[i].x,-cs[i].delta);
    int totl=0,totr=0;
    for(int i=L;i<=R;i++){
        if(cs[i].kind==1){
            //printf("%d %d %d %d\n",mid,cs[i].qpos,cs[i].cur+tmp[i],cs[i].k);
            if(cs[i].cur+tmp[i]>=cs[i].k){
                ql[totl++]=cs[i];
                //printf("<<%d %d l:%d tot:%d %d %d %d\n",L,R,mid,cs[i].qpos,cs[i].x,cs[i].y,cs[i].k);
            }
            else {
                cs[i].cur+=tmp[i];
                qr[totr++]=cs[i];
                //printf(">>%d %d r:%d tot:%d %d %d %d\n",L,R,mid,cs[i].qpos,cs[i].x,cs[i].y,cs[i].k);
            }
        }
        else {
            if(cs[i].y<=mid)ql[totl++]=cs[i];
            else qr[totr++]=cs[i];
        }
    }
    for(int i=0;i<totl;i++)cs[L+i]=ql[i];
    for(int i=0;i<totr;i++)cs[L+totl+i]=qr[i];
    //printf("%d %d %d %d-%d %d %d %d\n",L,totl-1,l,mid,L+totl,R,mid+1,r);
    cdq(L,L+totl-1,l,mid);
    cdq(L+totl,R,mid+1,r);
}
int main()
{
    while(~scanf("%d",&n)){
        int tot=0;
        memset(C,0,sizeof(C));
        memset(tmp,0,sizeof(tmp));
        for(int i=1;i<=n;i++){
            scanf("%d",&A[i]);
            cs[tot++]=point(i,A[i],0,0,0,1,0);
        }
        int qtot=0;
        scanf("%d",&q);
        for(int i=0,tp,l,r,x;i<q;i++){
            scanf("%d",&tp);
            if(tp==1){
                scanf("%d%d",&l,&x);
                cs[tot++]=point(l,A[l],0,0,0,-1,0);
                A[l]=x;
                cs[tot++]=point(l,A[l],0,0,0,1,0);
            }
            else {
                scanf("%d%d%d",&l,&r,&x);
                cs[tot++]=point(l,r,x,1,qtot++,0,0);
            }
        }
        cdq(0,tot-1,0,1000000000+100);
        for(int i=0;i<qtot;i++) printf("%d\n",ans[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值