HDU5412 CRB and Queries 整体二分

传送门

刚觉得最近写代码比较顺畅没什么Bug,cdq分治真是我的一个噩梦。。

整体二分模板题,带修改的区间第k小。

vjudge不知抽什么风,用不了,hdu忘了密码了一直在那里各种试,难受。。

写得比较鬼畜。

整体二分,传了三个l,r分别是二分答案的 el ,er ,对当前答案可能有贡献的修改区间的 l , r ,答案在当前二分区间中的询问区间 ql, qr

每次对el, er 取个mid,然后修改区间是按时间排好序的,按时间扫过去,在修改值大于mid的地方+1(区间第k小等价于大于等于它的数有len-k+1个),同时把这些区间往右放,其余区间往作放。

然后对于询问区间查询区间内1的个数,就知道了区间中大于等于mid的数的个数,如果个数大于等于len-k+1就把询问区间往右放,否则减去查询的值往左放。

el==er时对所有的询问区间更新答案。

注意的时我的这种鬼畜写法往右放时二分区间是mid,r,往左是l,mid-1,所以对于偶数长度的区间强制mid靠右才ok。。

跑得还蛮快的。

反正我觉得树套树优秀多了,虽然跑得慢一点。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<cmath>
const int N=300007;
typedef long long LL;
using namespace std;
int n,m,cq,v[N],ans[N];

template<typename T> void read(T &x) {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

struct node {
    int ti,pos,v,f;
    node(){}
    node(int ti,int pos,int v,int f):ti(ti),pos(pos),v(v),f(f){}
}cg[N],tp[N];
struct qs{
    int id,ti,l,r,k;
    qs(){}
    qs(int id,int ti,int l,int r,int k):id(id),ti(ti),l(l),r(r),k(k){}
}q[N],t[N];

int sum[N];
void add(int x,int v) {
    for(int i=x;i<=n;i+=(i&(-i)))
        sum[i]+=v;
}
int qry(int x) {
    int res=0;
    for(int i=x;i;i-=(i&(-i)))
        res+=sum[i];
    return res;
}

void cdq(int el,int er,int l,int r,int ql,int qr) {
    if(el>er||ql>qr) return; 
    if(el==er) {
        for(int i=ql;i<=qr;i++) ans[q[i].id]=el;
        return;    
    }
    int mid=((el+er)>>1); if((el+er)&1) mid++;
    int ll=l-1,rr=r+1,lx=ql-1,rx=qr+1,now=ql;
    for(int i=l;i<=r+1;i++) {
        while(now<=qr&&(i==r+1||q[now].ti<cg[i].ti)) {
            int dd=qry(q[now].r)-qry(q[now].l-1);
            if(dd>=q[now].k) t[--rx]=q[now];
            else { q[now].k-=dd; t[++lx]=q[now]; }
            now++;
        } if(i==r+1) break;
        if(cg[i].v>=mid) {
            tp[--rr]=cg[i];
            add(cg[i].pos,cg[i].f);
        }
        else tp[++ll]=cg[i];
    }
    int tr=rr,trr=rx;
    for(int i=rr;i<=r;i++) add(tp[i].pos,-tp[i].f);
    for(int i=l;i<=ll;i++) cg[i]=tp[i]; 
    for(int i=r;i>ll;i--) cg[i]=tp[tr++];
    for(int i=ql;i<=lx;i++) q[i]=t[i];
    for(int i=qr;i>lx;i--) q[i]=t[trr++];
    cdq(el,mid-1,l,ll,ql,lx); 
    cdq(mid,er,rr,r,rx,qr);   
} 

int main() {
    while(scanf("%d",&n)==1) {
        int el=1e9,er=0;
        for(int i=1;i<=n;i++) {
            read(v[i]); 
            el=min(el,v[i]); er=max(er,v[i]); 
            cg[i]=node(i,i,v[i],1);
        }
        read(m); cq=0;
        for(int i=1;i<=m;i++) {
            int o,x,y,k;
            read(o); read(x); read(y);
            if(o==1) {
                cg[++n]=node(n+i,x,v[x],-1);
                cg[++n]=node(n+i,x,y,1); v[x]=y;
                el=min(el,y); er=max(er,y); 
            }
            else {
                read(k);
                q[++cq]=qs(cq,n+i,x,y,y-x+1-k+1);
            }
        }
        cdq(el,er,1,n,1,cq);
        for(int i=1;i<=cq;i++) printf("%d\n",ans[i]); 
    }
    return 0;
}
/*
5
7 1 9 9 5 
1
2 3 3 1
*/
View Code

 

转载于:https://www.cnblogs.com/Achenchen/p/8399184.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值