P3332 [ZJOI2013]K大數查詢 - 整體二分-區間修改

題目鏈接:https://www.luogu.com.cn/problem/P3332
在這裏插入圖片描述
思路:我們區間修改用一個線段樹維護就可以了。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define mid (l+r>>1)

LL a[200000+10], sum[50000*4+10], laz[50000*4+10], rec[50000*4+10];
void BT(LL i, LL l, LL r){
    sum[i]=laz[i]=rec[i]=0;
    if(l==r){
        sum[i]=a[l];
        return ;
    }
    BT(i<<1, l, mid); BT((i<<1)+1, mid+1, r);
    sum[i]=sum[i<<1]+sum[(i<<1)+1];
}

void pushdown(LL i, LL l, LL r){
    if(rec[i]){//清空線段樹
        rec[i]=0;
        laz[i<<1]=laz[(i<<1)+1]=sum[i<<1]=sum[(i<<1)+1]=0;
        rec[(i<<1)]=rec[(i<<1)+1]=1;
    }
    if(laz[i]){
        laz[(i<<1)]+=laz[i]; laz[(i<<1)+1]+=laz[i];
        sum[(i<<1)]+=laz[i]*(mid-l+1);
        sum[(i<<1)+1]+=laz[i]*(r-mid);
        laz[i]=0;
    }
}

void add(LL i, LL l, LL r, LL L, LL R, LL v){

    if(l==L&&r==R){
        laz[i]+=v;
        sum[i]+=v*(r-l+1);
        return ;
    }
    if(laz[i]||rec[i]) pushdown(i, l, r);

    if(R<=mid) add(i<<1, l, mid, L, R, v);
    else if(L>mid) add((i<<1)+1, mid+1, r, L, R, v);
    else add(i<<1, l, mid, L, mid, v), add((i<<1)+1, mid+1, r, mid+1, R, v);
    sum[i]=sum[i<<1]+sum[(i<<1)+1];
}

LL query(LL i, LL l, LL r, LL L, LL R){
    if(l==L&&r==R){
        return sum[i];
    }
    if(laz[i]||rec[i]) pushdown(i, l, r);

    if(R<=mid) return query(i<<1, l, mid, L, R);
    if(L>mid) return query((i<<1)+1, mid+1, r, L, R);
    return query(i<<1, l, mid, L, mid)+query((i<<1)+1, mid+1, r, mid+1, R);
}

struct node{
    LL x, y, type, l, r, k, id;
    //值 添加/刪除 查詢/修改 區間 第k大 詢問數
}q[100000+5], q1[100000+5], q2[100000+5];
LL tot, totx, n, m, ans[100000+5];

void solve(LL ql, LL qr, LL l, LL r){
    if(ql>qr) return ;
    if(l==r){
        for(LL i=ql; i<=qr; i++){
            if(q[i].type==2){
                ans[q[i].id]=l;
            }
        }
        return ;
    }
    rec[1]=1, laz[1]=sum[1]=0;//清空線段樹

    LL t1=0, t2=0;
    for(LL i=ql; i<=qr; i++){
        if(q[i].type==1){
            if(q[i].x>mid){//第k大
                add(1, 1, n, q[i].l, q[i].r, q[i].y);
                q2[t2++]=q[i];
            }
            else{
                q1[t1++]=q[i];
            }
        }
        else{
            LL tt=query(1, 1, n, q[i].l, q[i].r);
            if(tt<q[i].k){
                q[i].k-=tt;
                q1[t1++]=q[i];
            }
            else{
                q2[t2++]=q[i];
            }
        }
    }
    for(LL i=0; i<t1; i++) q[ql+i]=q1[i];
    for(LL i=0; i<t2; i++) q[ql+t1+i]=q2[i];
    solve(ql, ql+t1-1, l, mid);
    solve(ql+t1, qr, mid+1, r);
}

int main(){

    tot=0, totx=0;
    scanf("%lld%lld", &n, &m);
    BT(1, 1, n);
    LL k, x, y, v;
    for(LL i=1; i<=m; i++){
        scanf("%lld%lld%lld%lld", &k, &x, &y, &v);
        if(k==1){
            q[++tot].x=v, q[tot].y=1, q[tot].type=1, q[tot].l=x, q[tot].r=y;
        }
        else{
            q[++tot].type=2, q[tot].k=v, q[tot].l=x, q[tot].r=y, q[tot].id=++totx;
        }
    }
    solve(1, m, -n, n);
    for(LL i=1; i<=totx; i++){
        printf("%lld\n", ans[i]);
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章