【知识点】分治相关

整体二分:

对于一类要求支持离线操作和询问达成某条件的操作次数的问题,可以把所有询问扔到一起二分答案。

具体地,每次对于操作区间$[l,r]$,将位于$[l,mid]$之间的操作做掉,然后依次判断答案位于$[l,r]$之间的每个询问的条件达没达成。

如果达成则该询问的答案$\leq mid$,扔到操作区间$[l,mid]$;否则该询问的答案$>mid$,扔到操作区间$[mid+1,r]$。

如果$l=r$则更新这些询问的答案,否则清空操作并继续递归左右两边的操作区间。

复杂度$O(n\log{n}\times 操作复杂度)$。

代码([POI2011]MET-Meteors):

#include<bits/stdc++.h>
#define maxn 300005
#define maxm 500005
#define inf 0x7fffffff
#define ll unsigned long long
#define rint register ll
#define debug(x) cerr<<#x<<": "<<x<<endl
#define fgx cerr<<"--------------"<<endl
#define dgx cerr<<"=============="<<endl

using namespace std;
ll P[maxn],L[maxn],R[maxn],n,m;
ll C[maxn<<1],A[maxn],ans[maxn]; 
vector<ll> nd[maxn],pos[maxn];
ll tp1[maxn],tp2[maxn];

inline ll read(){
    ll x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

inline ll lowbit(ll x){return x&(-x);}
inline void add(ll x,ll y){for(ll i=x;i<=2*m;i+=lowbit(i))C[i]+=y;}
inline ll qry(ll x){ll res=0;for(ll i=x;i;i-=lowbit(i))res+=C[i];return res;}

inline void solve(ll l,ll r){
    ll mid=l+r>>1,tot1=0,tot2=0;
    for(rint i=l;i<=mid;i++) add(L[i],A[i]),add(R[i]+1,-A[i]);
    for(rint i=0;i<nd[l].size();i++){
        rint u=nd[l][i],res=0;
        for(rint j=0;j<pos[u].size();j++) res+=qry(pos[u][j]);
        if(l==r) (res>=P[u])?(ans[u]=l):(ans[u]=-1);
        else{
            if(res>=P[u]) tp1[++tot1]=u;
            else P[u]-=res,tp2[++tot2]=u;
        }
    } 
    nd[l].clear();
    for(rint i=l;i<=mid;i++) add(L[i],-A[i]),add(R[i]+1,A[i]);
    if(l!=r){
        for(rint i=1;i<=tot1;i++) nd[l].push_back(tp1[i]);
        for(rint i=1;i<=tot2;i++) nd[mid+1].push_back(tp2[i]);
        solve(l,mid),solve(mid+1,r);
    }
}

int main(){
    n=read(),m=read();
    for(rint i=1;i<=m;i++)
        {ll x=read();pos[x].push_back(i),pos[x].push_back(i+m);}
    for(rint i=1;i<=n;i++) P[i]=read();
    ll k=read();
    for(rint i=1;i<=k;i++){
        L[i]=read(),R[i]=read(),A[i]=read();
        if(R[i]<L[i]) R[i]+=m;
    }
    for(rint i=1;i<=n;i++) nd[1].push_back(i); 
    solve(1,k);
    for(rint i=1;i<=n;i++){
        if(ans[i]==-1) printf("NIE\n");
        else printf("%lld\n",ans[i]);
    }
    return 0;
}
整体二分

猜你喜欢

转载自www.cnblogs.com/YSFAC/p/13198896.html