整体二分

更新日志 2024/11/26:增加带修例题

概念

将所有询问离线下来,对这个整体进行二分答案。

思路

通用的思路是,考虑对于单个问题,如何二分答案。

然后将所有二分答案压缩到一次二分答案之中。

更详细地,我们将所有询问储存在一起,每次二分答案时,将询问分成两类:当前 mid 已满足的和未满足的。

那么,下一次二分时,答案区间 [l,mid] 需要处理的询问就只有 mid 已满足的,反之同理。

同时,通常情况下,如果当前询问不满足,应当将其需求减去当前满足了的数量,让下一轮计算时只需要计算新增贡献即可。

当区间缩为一点时,答案固定。

细节

通常情况下,整体二分会涉及到前缀和、树状数组、线段树等,这时候每次递归下一轮前都要对其清空。考虑到直接清空复杂度太高,我们只需要把所有进行过操作的部分减回去即可。

另外,在分类询问时,可以开一个临时数组储存分类结果,最后用它覆盖原数组即可。

如果存在无解情况,记得把对应边界开大 \(1\)

代码

void solve(int x,int y,int l,int r){//x,y询问区间 l,r答案区间
    if(l==r){
        rep(i,x,y)ans[arr[i]]=l;//记录答案
        return;
    }
    int mid=l+r>>1;
    rep(i,l,mid){
        //统计答案贡献
    }
    int cnt=0;
    rep(i,x,y){
        ll num=0;
        //计算当前答案
        if(num>=ned[arr[i]]){//可行
            can[i]=true;
            cnt++;
        }else{
            can[i]=false;
            ned[arr[i]]-=num;//减去当前贡献
        }
    }
    int cnt1=0,cnt2=0;
    //分类
    rep(i,x,y){
        if(can[i]){
            tmp[x+cnt1]=arr[i];
            cnt1++;
        }else{
            tmp[x+cnt+cnt2]=arr[i];
            cnt2++;
        }
    }
    rep(i,x,y)arr[i]=tmp[i];
    rep(i,l,mid){
        //退回贡献
    }
    solve(x,x+cnt-1,l,mid);solve(x+cnt,y,mid+1,r);//递归下一轮
}

修改操作

把修改和询问放到同一个序列中,统一记作操作序列,二分时分类这个序列即可。

视情况将修改操作也分类,看是否会对区间造成影响,这个主要还是要视具体情况而定。

例题

MET-Meteors

代码

前注:非题解,不做详细讲解

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef double db;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
template <typename Type>
using vec=vector<Type>;
template <typename Type>
using grheap=priority_queue<Type>;
template <typename Type>
using lrheap=priority_queue<Type,vector<Type>,greater<Type> >;
#define fir first
#define sec second
#define pub push_back
#define pob pop_back
#define puf push_front
#define pof pop_front
#define chmax(a,b) a=max(a,b)
#define chmin(a,b) a=min(a,b)
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)

const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7/*998244353*/;

const int N=3e5+5;

int n,m,k;
vec<int> plcs[N];
int ned[N];
struct rain{int l,r,a;}rs[N];
int arr[N],tmp[N];
int ans[N];
bool can[N];

struct fenwick{
    ll dat[N*2];
    int lowbit(int x){return x&-x;}
    void add(int x,ll a){
        while(x<=m*2){
            dat[x]+=a;
            x+=lowbit(x);
        }
    }
    ll query(int x){
        ll res=0;
        while(x>0){
            res+=dat[x];
            x-=lowbit(x);
        }
        return res;
    }
}fwt;

void solve(int x,int y,int l,int r){
    if(l==r){
        rep(i,x,y)ans[arr[i]]=l;
        return;
    }
    int mid=l+r>>1;
    rep(i,l,mid){
        fwt.add(rs[i].l,rs[i].a);
        fwt.add(rs[i].r+1,-rs[i].a);
    }
    int cnt=0;
    rep(i,x,y){
        ll num=0;
        for(auto j:plcs[arr[i]]){
            num+=fwt.query(j)+fwt.query(j+m);
            if(num>=ned[arr[i]])break;
        }
        if(num>=ned[arr[i]]){
            can[i]=true;
            cnt++;
        }else{
            can[i]=false;
            ned[arr[i]]-=num;
        }
    }
    int cnt1=0,cnt2=0;
    rep(i,x,y){
        if(can[i]){
            tmp[x+cnt1]=arr[i];
            cnt1++;
        }else{
            tmp[x+cnt+cnt2]=arr[i];
            cnt2++;
        }
    }
    rep(i,x,y)arr[i]=tmp[i];
    rep(i,l,mid){
        fwt.add(rs[i].l,-rs[i].a);
        fwt.add(rs[i].r+1,rs[i].a);
    }
    solve(x,x+cnt-1,l,mid);solve(x+cnt,y,mid+1,r);
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    int o;
    rep(i,1,m){cin>>o;plcs[o].pub(i);}
    rep(i,1,n)cin>>ned[i];
    cin>>k;
    rep(i,1,k){
        cin>>rs[i].l>>rs[i].r>>rs[i].a;
        if(rs[i].r<rs[i].l)rs[i].r+=m;
    }
    rep(i,1,n)arr[i]=i;
    solve(1,n,1,k+1);
    rep(i,1,n){
        if(ans[i]==k+1)cout<<"NIE\n";
        else cout<<ans[i]<<"\n";
    }
    return 0;
}

带修

K大数查询

代码

前注:非题解,不做详细讲解

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef double db;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<int,ll> pil;
typedef pair<ll,int> pli;
template <typename Type>
using vec=vector<Type>;
template <typename Type>
using grheap=priority_queue<Type>;
template <typename Type>
using lrheap=priority_queue<Type,vector<Type>,greater<Type> >;
#define fir first
#define sec second
#define pub push_back
#define pob pop_back
#define puf push_front
#define pof pop_front
#define chmax(a,b) a=max(a,b)
#define chmin(a,b) a=min(a,b)
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=y;i>=x;i--)

const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7/*998244353*/;

const int N=5e4+5;

int n,m;
struct op{
    int tp;
    int l,r;ll c;
}os[N];
int xs;
ll x[N];
int arr[N],tmp[N];
int ans[N];
bool lft[N];

struct segment{
    ll dat[N*4],laz[N*4];
    void update(int x){
        dat[x]=dat[x*2]+dat[x*2+1];
    }
    void pushdown(int x,int l,int r){
        if(laz[x]==0)return;
        int m=l+r>>1;
        dat[x*2]+=laz[x]*(m-l+1);
        dat[x*2+1]+=laz[x]*(r-m);
        laz[x*2]+=laz[x];
        laz[x*2+1]+=laz[x];
        laz[x]=0;
    }
    void add(int lq,int rq,ll v,int x=1,int l=1,int r=n){
        if(lq<=l&&r<=rq){
            dat[x]+=v*(r-l+1);
            laz[x]+=v;
            return;
        }
        pushdown(x,l,r);
        int m=l+r>>1;
        if(lq<=m)add(lq,rq,v,x*2,l,m);  
        if(m<rq)add(lq,rq,v,x*2+1,m+1,r);
        update(x);
    }
    ll query(int lq,int rq,int x=1,int l=1,int r=n){
        if(lq<=l&&r<=rq){
            return dat[x];
        }
        pushdown(x,l,r);
        int m=l+r>>1;
        ll res=0;
        if(lq<=m)res+=query(lq,rq,x*2,l,m);
        if(m<rq)res+=query(lq,rq,x*2+1,m+1,r);
        return res;
    }
}seg;

void solve(int x,int y,int l,int r){
    if(l>r)return;
    if(l==r){
        rep(i,x,y)ans[arr[i]]=l;
        return;
    }
    int mid=l+r+1>>1;
    int cnt=0;
    rep(i,x,y){
        op &now=os[arr[i]];
        if(now.tp==1){
            if(now.c>=mid){
                seg.add(now.l,now.r,1);
                lft[i]=false;
            }else{
                cnt++;
                lft[i]=true;
            }
        }else{
            ll num=seg.query(now.l,now.r);
            if(num>=now.c){
                lft[i]=false;
            }else{
                cnt++;
                lft[i]=true;
                now.c-=num;
            }
        }
    }
    int cnt1=0,cnt2=0;
    rep(i,x,y){
        op &now=os[arr[i]];
        if(now.tp==1&&now.c>=mid)seg.add(now.l,now.r,-1);
        if(lft[i]){
            tmp[x+cnt1]=arr[i];
            cnt1++;
        }else{
            tmp[x+cnt+cnt2]=arr[i];
            cnt2++;
        }
    }
    rep(i,x,y)arr[i]=tmp[i];
    solve(x,x+cnt-1,l,mid-1);
    solve(x+cnt,y,mid,r);
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    rep(i,1,m){
        cin>>os[i].tp>>os[i].l>>os[i].r>>os[i].c;
        if(os[i].tp==1)x[++xs]=os[i].c;
    }
    sort(x+1,x+1+xs);
    xs=unique(x+1,x+1+xs)-x-1;
    rep(i,1,m){
        arr[i]=i;
        if(os[i].tp==1)os[i].c=lower_bound(x+1,x+1+xs,os[i].c)-x;
    }
    solve(1,m,1,xs);
    rep(i,1,m){
        if(os[i].tp==2)cout<<x[ans[i]]<<"\n";
    }
    return 0;
}
posted @ 2024-11-25 12:08  HarlemBlog  阅读(3)  评论(0编辑  收藏  举报