BZOJ 2527: [Poi2011]Meteors [整体二分]

传送门

题意:

一个星球环形带上分为 $M$ 个区域,$n$个国家,$k$天,每个区域可能有若干国家的陨石收集器,每一天有一段连续区域下陨石雨,
其上所有收集器都为本国家收集到 $D_i$ 的陨石,每个国家有一定的陨石需求量$P_i$,求每个国家第几天收集陨石量恰好满足需求
$1 \le n,m,k \le 3∗10^5\quad  1 \le A_i,P_i < 10^9$


整体二分

$zyz:$整体二分是在权值上进行$CDQ$分治

我觉得更像是说$:$整体二分是在答案上进行$CDQ$分治

整体二分是二分答案在数据结构题上的扩展

因为数据结构题二分的答案通常是第几个操作之后,需要进行哪些操作之后才能判断

核心就是维护一个$cur$数组保存当前的影响

$Sol(l,r,S)\ l,r$是当前

操作$[l,mid]$的影响(对答案的贡献),加上$cur$看看与询问相比大小分成左右递归分治

询问集合保存编号就好了

是不是命名有点奇怪,q是操作,a是询问。。。所以说无视这份代码吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define lc x<<1
#define rc x<<1|1
#define lson x<<1,l,mid
#define rson x<<1|1,mid+1,r
const int N=3e5+5,INF=1e9;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    return x*f;
}
int n,m,k;
struct edge{
    int v,ne;
}e[N];
int h[N],cnt;
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
}
int a[N],t1[N],t2[N],lim[N];
struct Meteor{
    int l,r,w;
}q[N];
ll c[N];
inline int lowbit(int x){return x&-x;}
inline void _add(int p,ll v){for(;p<=m;p+=lowbit(p)) c[p]+=v;}
inline ll sum(int p){
    ll re=0;
    for(;p;p-=lowbit(p)) re+=c[p];
    return re;
}
inline void add(int l,int r,int v){
    _add(l,v);_add(r+1,-v);
}
ll cur[N];
int ans[N];
void Sol(int l,int r,int sl,int sr){//printf("Sol %d %d %d %d\n",l,r,sl,sr);
    if(sl>sr) return;
    if(l==r){
        for(int i=sl;i<=sr;i++) ans[a[i]]=l;
        return;
    }
    int mid=(l+r)>>1;
    for(int i=l;i<=mid;i++){
        if(q[i].l<=q[i].r) add(q[i].l,q[i].r,q[i].w);
        else add(1,q[i].r,q[i].w),add(q[i].l,m,q[i].w);
    }
    int p1=0,p2=0;
    for(int i=sl;i<=sr;i++){
        int u=a[i];ll s=cur[u],p=lim[u];
        for(int k=h[u];k;k=e[k].ne)
            if((s+=sum(e[k].v))>=p) break;
        if(s>=p) t1[++p1]=u;
        else t2[++p2]=u,cur[u]=s;
    }
    for(int i=l;i<=mid;i++){
        if(q[i].l<=q[i].r) add(q[i].l,q[i].r,-q[i].w);
        else add(1,q[i].r,-q[i].w),add(q[i].l,m,-q[i].w);
    }
    for(int i=1;i<=p1;i++) a[sl+i-1]=t1[i];
    for(int i=1;i<=p2;i++) a[sl+p1+i-1]=t2[i];
    Sol(l,mid,sl,sl+p1-1);
    Sol(mid+1,r,sl+p1,sr);
}
int main(){
    freopen("in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=m;i++) ins(read(),i);
    for(int i=1;i<=n;i++) lim[i]=read(),a[i]=i;
    k=read();
    for(int i=1;i<=k;i++) q[i].l=read(),q[i].r=read(),q[i].w=read();
    q[++k].l=1;q[k].r=m;q[k].w=INF;
    Sol(1,k,1,n);
    //for(int i=1;i<=n;i++) printf("%d %d %lld\n",i,ans[i],cur[i]);
    for(int i=1;i<=n;i++){
        if(ans[i]!=k) printf("%d\n",ans[i]);
        else puts("NIE");
    }
}

 

posted @ 2017-02-26 11:07  Candy?  阅读(613)  评论(0编辑  收藏  举报