V.I.[POI2011]MET-Meteors
套上整体二分,然后用BIT统计区间里每个国家收到多少陨石就行了。
听说有人还有用线段树上二分之类奇怪的东西,但是真的没有必要。
时间复杂度 \(O(n\log^2n)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,a[300100],q,L[300100],R[300100],V[300100],p[300100],res[300100];
bool ok[300100];
vector<int>v[300100];
ll t[300100];
void ADD(int x,int y){while(x<=m)t[x]+=y,x+=x&-x;}
ll SUM(int x){ll ret=0;while(x)ret+=t[x],x-=x&-x;return ret;}
void solve(int l,int r,int ll,int rr){
if(l==r){for(int i=ll;i<=rr;i++)res[p[i]]=l;return;}
// printf("[%d,%d]:",l,r);for(int i=ll;i<=rr;i++)printf("%d ",p[i]);puts("");
if(ll>rr)return;
int mid=(l+r)>>1;
for(int i=l;i<=mid;i++)if(L[i]<=R[i])ADD(L[i],V[i]),ADD(R[i]+1,-V[i]);else ADD(1,V[i]),ADD(R[i]+1,-V[i]),ADD(L[i],V[i]);
for(int i=ll;i<=rr;i++){
long long sum=0;
for(auto j:v[p[i]]){
sum+=SUM(j);
if(sum>=a[p[i]])break;
}
// printf("%d\n",sum);
if(sum>=a[p[i]])ok[p[i]]=true;else ok[p[i]]=false,a[p[i]]-=sum;
}
for(int i=l;i<=mid;i++)if(L[i]<=R[i])ADD(L[i],-V[i]),ADD(R[i]+1,V[i]);else ADD(1,-V[i]),ADD(R[i]+1,V[i]),ADD(L[i],-V[i]);
sort(p+ll,p+rr+1,[](int u,int v){return ok[u]>ok[v];});
int MID=ll-1;while(MID<rr&&ok[p[MID+1]])MID++;
for(int i=ll;i<=rr;i++)ok[p[i]]=false;
solve(l,mid,ll,MID),solve(mid+1,r,MID+1,rr);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,x;i<=m;i++)scanf("%d",&x),v[x].push_back(i);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
scanf("%d",&q);
for(int i=1;i<=q;i++)scanf("%d%d%d",&L[i],&R[i],&V[i]);
q++,L[q]=1,R[q]=n,V[q]=0x3f3f3f3f;
for(int i=1;i<=n;i++)p[i]=i;
solve(1,q,1,n);
for(int i=1;i<=n;i++)if(res[i]==q)puts("NIE");else printf("%d\n",res[i]);
return 0;
}