【BZOJ2527】Meteors(POI2011)-整体二分+树状数组

测试地址:Meteors
题目大意:一个环上有m个区域,有n个国家,每个国家管辖一些区域,有k场陨石雨陆续降落,每场陨石雨会给一个环上的区间内的每个区域提供Ai颗陨石,现在每个国家都有采样任务,即要在他们管辖的区域中收集共Pi颗陨石,问每个国家最早在第几场陨石雨后就可以完成任务。
做法:本题需要用到整体二分+树状数组。
首先,如果只有一个询问,我们就可以用二分答案+树状数组统计来算出答案(区间加,单点修改可以差分后用树状数组维护),时间复杂度为O(nlog2n)。而这题有多个询问,又没有强制在线,因此考虑整体二分。
我们需要完成函数solve(s,t,l,r),表示要处理的询问区间为[s,t],它们的答案已知在区间[l,r]中。那么按照套路,我们令区间[l,r]的中点为mid,考虑在区间[l,mid]的所有操作对询问的影响,这一步可以用树状数组完成,然后将所有询问进一步分治求解。我们来分析该算法的时间复杂度,显然所有操作的总时间复杂度是O(nlog2n)的,而对于一个询问,它会被计算logn次,那么所有询问的总时间复杂度就是O(nlog2n)的,因此算法的总时间复杂度就是O(nlog2n),可以通过此题。
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,k,first[300010]={0},nxt[300010],ans[300010];
int L[300010],R[300010];
ll sum[300010]={0},A[300010];
struct query
{
    int id;
    ll limit,sum;
}q[300010],q1[300010],q2[300010];

int lowbit(int x)
{
    return x&(-x);
}

void add(int l,int r,ll c)
{
    for(int i=l;i<=m;i+=lowbit(i))
        sum[i]+=c;
    for(int i=r+1;i<=m;i+=lowbit(i))
        sum[i]-=c;
}

ll query(int x)
{
    ll ans=0;
    for(int i=x;i;i-=lowbit(i))
        ans+=sum[i];
    return ans;
}

void solve(int s,int t,int l,int r)
{
    if (s>t) return;
    if (l==r)
    {
        for(int i=s;i<=t;i++)
            ans[q[i].id]=l;
        return;
    }

    int mid=(l+r)>>1,tot1=0,tot2=0;
    for(int i=l;i<=mid;i++)
    {
        if (L[i]<=R[i]) add(L[i],R[i],A[i]);
        else add(1,R[i],A[i]),add(L[i],m,A[i]);
    }

    for(int i=s;i<=t;i++)
    {
        ll s=0;
        int now=first[q[i].id];
        while(now)
        {
            s+=query(now);
            if (q[i].sum+s>=q[i].limit) break;
            now=nxt[now];
        }
        if (q[i].sum+s>=q[i].limit) q1[++tot1]=q[i];
        else q[i].sum+=s,q2[++tot2]=q[i];
    }
    for(int i=1;i<=tot1;i++)
        q[s+i-1]=q1[i];
    for(int i=1;i<=tot2;i++)
        q[s+tot1+i-1]=q2[i];

    for(int i=l;i<=mid;i++)
    {
        if (L[i]<=R[i]) add(L[i],R[i],-A[i]);
        else add(1,R[i],-A[i]),add(L[i],m,-A[i]);
    }

    solve(s,s+tot1-1,l,mid);
    solve(s+tot1,t,mid+1,r);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        nxt[i]=first[x];
        first[x]=i;
    }

    for(int i=1;i<=n;i++)
        scanf("%lld",&q[i].limit);
    scanf("%d",&k);
    for(int i=1;i<=k;i++)
        scanf("%d%d%lld",&L[i],&R[i],&A[i]);
    for(int i=1;i<=n;i++)
        q[i].id=i,q[i].sum=0;
    solve(1,n,1,k+1);
    for(int i=1;i<=n;i++)
    {
        if (ans[i]==k+1) printf("NIE\n");
        else printf("%d\n",ans[i]);
    }

    return 0;
}
posted @ 2018-05-20 20:19  Maxwei_wzj  阅读(70)  评论(0编辑  收藏  举报