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