整体二分
区间[l,r]为当前处理修改操作区间,即陨石雨的区间,[L,R]为询问操作区间,即每个国家,那么执行[l,r]区间的修改,对于[L,R]中的每个国家,用树状数组查询收集到的陨石,如果大于希望获得的数量,那么答案就在[l,mid]的区间里,否则在[mid+1,r]的区间里,递归处理就可以了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#define N 300010
using namespace std;
typedef long long ll;
int n,m,x,t,q;
int it[N],Ans[N];
ll A[N];
vector<int> p[N];
struct ct{
int wnt,g;
}c[N],c1[N],c2[N];
struct stp{
int l,r,aed;
}s[N];
inline void reaD(int &x){
char Ch=getchar();x=0;
for(;Ch>'9'||Ch<'0';Ch=getchar());
for(;Ch>='0'&&Ch<='9';x=x*10+Ch-'0',Ch=getchar());
}
inline void add(int x,int y){
for(;x;x-=x&-x)
if(it[x]==t) A[x]+=y;
else it[x]=t,A[x]=y;
}
inline void add(int x,int y,int w){
add(y,w);
add(x-1,-w);
}
inline ll query(int x){
ll r=0;
for(;x<=m;x+=x&-x)
if(it[x]==t) r+=A[x];
return r;
}
void solve(int l,int r,int L,int R){
if(L>R) return;
++t;
if(l==r){
if(s[l].l<=s[l].r) add(s[l].l,s[l].r,s[l].aed);
else add(1,s[l].r,s[l].aed),add(s[l].l,m,s[l].aed);
for(int i=L;i<=R;i++){
ll tot=0;
for(int j=0;j<p[c[i].g].size();j++)
if((tot+=query(p[c[i].g][j]))>=c[i].wnt) break;
if(tot>=c[i].wnt) Ans[c[i].g]=r;
}
return ;
}
int mid=l+r>>1;
for(int i=l;i<=mid;i++){
if(s[i].l<=s[i].r) add(s[i].l,s[i].r,s[i].aed);
else add(1,s[i].r,s[i].aed),add(s[i].l,m,s[i].aed);
}
int t1=0,t2=0;
for(int i=L;i<=R;i++){
ll tot=0;
for(int j=0;j<p[c[i].g].size();j++)
if((tot+=query(p[c[i].g][j]))>c[i].wnt) break;
if(tot>=c[i].wnt) c1[++t1]=c[i];
else c2[++t2]=c[i],c2[t2].wnt-=tot;
}
for(int i=1;i<=t1;i++) c[L+i-1]=c1[i];
for(int i=1;i<=t2;i++) c[R-t2+i]=c2[i];
solve(l,mid,L,L+t1-1);
solve(mid+1,r,L+t1,R);
}
int main(){
reaD(n); reaD(m);
for(int i=1;i<=m;i++){
reaD(x); p[x].push_back(i);
}
for(int i=1;i<=n;i++) reaD(c[i].wnt),c[i].g=i;
reaD(q);
for(int i=1;i<=q;i++) reaD(s[i].l),reaD(s[i].r),reaD(s[i].aed);
solve(1,q,1,n);
for(int i=1;i<=n;i++)
if(!Ans[i]) puts("NIE");
else printf("%d\n",Ans[i]);
return 0;
}