2527: [Poi2011]Meteors
Description
Byteotian Interstellar Union有N个成员国。现在它发现了一颗新的星球,这颗星球的轨道被分为M份(第M份和第1份相邻),第i份上有第Ai个国家的太空站。
这个星球经常会下陨石雨。BIU已经预测了接下来K场陨石雨的情况。
BIU的第i个成员国希望能够收集Pi单位的陨石样本。你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。
Input
第一行是两个数N,M。
第二行有M个数,第i个数Oi表示第i段轨道上有第Oi个国家的太空站。
第三行有N个数,第i个数Pi表示第i个国家希望收集的陨石数量。
第四行有一个数K,表示BIU预测了接下来的K场陨石雨。
接下来K行,每行有三个数Li,Ri,Ai,表示第K场陨石雨的发生地点在从Li顺时针到Ri的区间中(如果Li<=Ri,就是Li,Li+1,…,Ri,否则就是Ri,Ri+1,…,m-1,m,1,…,Li),向区间中的每个太空站提供Ai单位的陨石样本。
Output
N行。第i行的数Wi表示第i个国家在第Wi波陨石雨之后能够收集到足够的陨石样本。如果到第K波结束后仍然收集不到,输出NIE。
数据范围:
1<=n,m,k<=3*10^5
1<=Pi<=10^9
1<=Ai<10^9
Sample Input
3 5
1 3 2 1 3
10 5 7
3
4 2 4
1 3 1
3 5 2
Sample Output
3
NIE
1
【解题报告】
来自http://victorwonder.is-programmer.com/posts/70210.html
对于单个查询(假设为第i个国家),我们可以二分k,每次对于一个区间[l,r],手动模拟一下在第mid场流星雨过后,第i个国家一共收集到了多少单位的陨石,如果比pi大,那么答案在[l,mid]范围内,否则答案在[mid+1,r]范围内。
对于多组查询,我们也可以这么做。首先,我们需要用一个列表id[]记录所有查询的编号,刚开始的时候,id[]自然是递增的.同时,我们用一个数组cur[i]记录下,第i个国家在l-1场流星雨过后,收集到的陨石的数目。
主过程为void solve(int head,int tail,int l,int r),表示对于id[head]到id[tail]的所有询问,在[l,r]范围内查询答案,通过上一层的操作,我们保证id[head]到id[tail]的所有询问的答案都在[l,r]范围内。
首先,我们先模拟[l,mid]这么多次操作(在询问重新划分之后,必须要再次模拟,将数组清空),用树状数组或者是线段树计算出在[l,mid]场流星雨之后,每个空间站收集到的陨石的数目。
然后我们查询,每个国家收集到的陨石的数目,要注意的是,我们需要用链表储存每个国家对应的空间站,并且一一枚举,用tmp[id[i]]表示国家id[i]收集到的陨石的数目。
那么从[1,mid]这么多次操作之后,国家id[i]收集到的陨石数目就是tmp[id[i]]+cur[id[i]],如果tmp[id[i]]+cur[id[i]]>p[id[i]],那么表明对于国家id[i],其答案在[l,mid]这个范围内,否则其答案在[mid+1,r]范围内,并将tmp[id[i]]累加到cur[id[i]]上。
还有一个坑点是,tmp[id[i]]可能很大,会爆掉long long,所以如果枚举一个国家的所有空间站的时候,发现tmp[id[i]]已经大于p[id[i]]了,那么就break好了,不然会出错。
因为可能会出现怎么也无法满足的情况,所以我们需要多增加一场流星雨,这场流星雨的数量为infi,保证能够让所有国家都满足要求,那么最后,对于所有答案为k+1的询问,输出NIE就行了。
总的来说,整体二分就是将所有询问一起二分,然后获得每个询问的答案。
注意这道题有一个坑点是会爆long long!!!
代码如下:
/**************************************************************
Problem: 2527
User: onepointo
Language: C++
Result: Accepted
Time:16128 ms
Memory:19572 kb
****************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 300010
#define inf 0x3f3f3f3f
#define l_inf (1LL<<63)-1
#define lowbit(x) (x&(-x))
int n,m,k;
long long t[N];
int ans[N],he[N],ne[N];
struct data {int need,id;long long cur;}a[N],q[N];
struct Rain {int l,r,v;}b[N];
void add(int x,long long v)
{
if(!x) ++x;
for(int i=x;i<=m;i+=lowbit(i)) t[i]+=v;
}
void update(int l,int r,long long v)
{
add(l,v);add(r+1,-v);
}
long long sum(int x)
{
long long ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=t[i];
return ans;
}
void solve(int l,int r,int h,int t)
{
if(h>t) return;
if(l==r)
{
for(int i=h;i<=t;i++) ans[a[i].id]=l;
return;
}
int mid=(l+r)>>1;
for(int i=l;i<=mid;i++)
if(b[i].l<=b[i].r)
update(b[i].l,b[i].r,b[i].v);
else update(1,b[i].r,b[i].v),update(b[i].l,m,b[i].v);
int t1=h-1,t2=t+1;
for(int i=h;i<=t;i++)
{
long long tmp=0;
for(int j=he[a[i].id];j;j=ne[j])
{
tmp+=sum(j);
if(a[i].cur+tmp>=a[i].need) break; //防止爆long long
}
if(a[i].cur+tmp>=a[i].need) q[++t1]=a[i];
else a[i].cur+=tmp,q[--t2]=a[i];
}
for(int i=h;i<=t;i++) a[i]=q[i];
for(int i=l;i<=mid;i++)
if(b[i].l<=b[i].r) update(b[i].l,b[i].r,-b[i].v);
else update(1,b[i].r,-b[i].v),update(b[i].l,m,-b[i].v);
solve(l,mid,h,t1);
solve(mid+1,r,t2,t);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
ne[i]=he[x],he[x]=i;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].need);
a[i].id=i;
}
scanf("%d",&k);
for(int i=1;i<=k;i++) scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].v);
b[++k].l=1;b[k].r=m;b[k].v=inf;
solve(1,k,1,n);
for(int i=1;i<=n;i++)
{
if(ans[i]==k) printf("NIE\n");
else printf("%d\n",ans[i]);
}
return 0;
}