P3527 [POI2011]MET-Meteors 题解
考虑整体二分。solve(L,R,l,r)
表示解决的子问题为答案区间在 \([L,R]\) 内的所有问题 \(q_l...q_r\)。边界条件很容易,主要是考虑如何二分。\([L,R]\) 这一维相当于是描述的时间,那么考虑一个 \(mid\),然后把所有 \([L,mid]\) 时刻的修改加进树状数组,这样区间和就变成单点修改了。然后扫一遍 \([L,R]\) 的询问,如果此时已经满足条件,说明它的答案区间为 \([L,mid]\),否则是 \([mid+1,R]\)。复杂度为 \(O(n\log m\log k)\)。
注意加和可能爆ll,所以需要边加边判断;注意不要使用 memset
,虽然其有小常数,但是复杂度可能会多一个 \(\log\) 导致TLE!
点击查看代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
inline int min(const int &x,const int &y){return x<y?x:y;}
inline int rd(){
int res=0;char c=getchar();
for(;!isdigit(c);c=getchar());
for(;isdigit(c);c=getchar())res=(res<<1)+(res<<3)+(c-'0');
return res;
}
void wt(int x){if(x>9)wt(x/10);putchar(x%10+'0');}
const int N=3e5+13;
int n,m,k,b[N],q[N],lq[N],rq[N],ans[N];
vector<int> a[N];
struct Node{int l,r,w;}c[N];
struct BIT{
ll t[N];
#define lowbit(x) (x&-x)
inline void add(int x,int k){for(;x<=m;x+=lowbit(x))t[x]+=k;}
inline ll sum(int x){ll res=0;for(;x;x-=lowbit(x))res+=t[x];return res;}
}T;
void solve(int L,int R,int l,int r){
if(l>r) return;
if(L==R){
for(int i=l;i<=r;++i) ans[q[i]]=L;
return;
}
int mid=(L+R)>>1;
for(int i=L;i<=min(mid,k);++i){
if(c[i].l<=c[i].r) T.add(c[i].l,c[i].w),T.add(c[i].r+1,-c[i].w);
else T.add(1,c[i].w),T.add(c[i].r+1,-c[i].w),T.add(c[i].l,c[i].w);
}
int lt=0,rt=0;
for(int i=l;i<=r;++i){
ll res=0;int lim=a[q[i]].size();bool flag=1;
for(int j=0;j<lim;++j){
res+=T.sum(a[q[i]][j]);
if(res>=b[q[i]]){flag=0;break;}
}
if(!flag) lq[++lt]=q[i];
else rq[++rt]=q[i],b[q[i]]-=res;
}
for(int i=L;i<=min(mid,k);++i){
if(c[i].l<=c[i].r) T.add(c[i].l,-c[i].w),T.add(c[i].r+1,c[i].w);
else T.add(1,-c[i].w),T.add(c[i].r+1,c[i].w),T.add(c[i].l,-c[i].w);
}
for(int i=1;i<=lt;++i) q[l+i-1]=lq[i];
for(int i=1;i<=rt;++i) q[l+lt+i-1]=rq[i];
solve(L,mid,l,l+lt-1);
solve(mid+1,R,l+lt,r);
}
int main(){
n=rd(),m=rd();
for(int i=1,x;i<=m;++i){
x=rd();
a[x].push_back(i);
}
for(int i=1;i<=n;++i) b[i]=rd();
k=rd();
for(int i=1;i<=k;++i) c[i].l=rd(),c[i].r=rd(),c[i].w=rd();
for(int i=1;i<=n;++i) q[i]=i;
solve(1,k+1,1,n);
for(int i=1;i<=n;++i){
if(ans[i]==k+1) puts("NIE");
else wt(ans[i]),putchar('\n');
}
return 0;
}