首先看上来就可以进行二分,但是答案是n个,所以我们进行整体二分,每次分成两个集合,一个集合可以完成,一个不可以,然后继续二分即可。
学习了Vergil学长的做法,偷懒用了vector,然后luogu上90分,懒得用数组去模拟实现了(都是细节)——by VANE
#include<bits/stdc++.h> using namespace std; #define N 300005 long long c[N]; int n,m,k,goal[N],ans[N]; int L[N],R[N],A[N],vis_cnt; int vis[N]; vector<int> S,g[N]; void clear(int x) { if(vis[x]==vis_cnt) return; vis[x]=vis_cnt; c[x]=0; } inline int read() { int x=0;char ch=getchar();int f=1; while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-f;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘) {x=x*10+ch-‘0‘;ch=getchar();} return x*f; } void add(int x,int z) { for(;x<=m;x+=x&-x) { clear(x); c[x]+=z; } } long long sum(int x) { long long w=0; for(;x;x-=x&-x) { clear(x); w+=c[x]; } return w; } void solve(int l,int r,vector<int> S) { if(l==r) { int siz=S.size(); for(int j=0;j<siz;++j) ans[S[j]]=l; return; } int mid=l+r>>1; vis_cnt++; for(int i=l;i<=mid;++i) { if(L[i]<=R[i]) { add(L[i],A[i]); add(R[i]+1,-A[i]); } else { add(L[i],A[i]); add(1,A[i]); add(R[i]+1,-A[i]); } } int siz=S.size(); vector<int> S1,S2; for(int j=0;j<siz;++j) { int u=S[j]; int sizz=g[u].size(); long long w=0; bool flag=0; for(int b=0;b<sizz;++b) { w+=sum(g[u][b]); if(w>=goal[u]) { S1.push_back(u); flag=1; break; } } if(!flag) { S2.push_back(u); goal[u]-=w; } } if(S1.size()) solve(l,mid,S1); if(S2.size()) solve(mid+1,r,S2); } int main() { n=read();m=read(); for(int i=1;i<=m;++i) g[read()].push_back(i); for(int i=1;i<=n;++i) goal[i]=read(); k=read(); for(int i=1;i<=k;++i) { L[i]=read(); R[i]=read(); A[i]=read(); } for(int i=1;i<=n;++i) S.push_back(i); solve(1,k+1,S); for(int i=1;i<=n;++i) if(ans[i]==k+1) puts("NIE"); else printf("%d\n",ans[i]); return 0; }