题目:洛谷P3527。
题目大意:
n个国家在某星球上建立了m个空间站(一个空间站只属于一个国家),空间站围成一个环。
现在知道要下k天陨石,每天都在一个区间内下,每个点都下同样多的(若r>l,则说明区间是(1~r和l~m))。
每个国家有一个目标陨石数。
问每个国家最早在什么时候达到目标陨石数。若下完了还达不到,则输出NIE。
解题思路:
整体二分。
对所有的国家一起二分,用树状数组维护前缀(后缀)。
对于每个答案,将能达到目标的国家和达不到的国家分开,然后继续二分即可。
时间复杂度(O(nlog^2 n))。
线段树被卡常┭┮﹏┭┮
C++ Code:
#include<cstdio> #include<vector> #include<cctype> #define LoveLive long long const int M=500005,N=300005; int k,n,m,P[N],q[N],ans[N],now,tmp[N];std::vector<int>a[N]; LoveLive Bit[M]; bool type[N]; inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } struct stars{ int l,r,s; }d[N]; inline void add(int i,int a){for(;i<=m;i+=i&-i)Bit[i]+=a;} inline LoveLive query(int i){LoveLive a=0;for(;i;i-=i&-i)a+=Bit[i];return a;} inline void update(int tm,int det){ if(d[tm].l<=d[tm].r)add(d[tm].l,det*d[tm].s),add(d[tm].r+1,-det*d[tm].s);else add(1,det*d[tm].s),add(d[tm].r+1,-det*d[tm].s),add(d[tm].l,det*d[tm].s); } void solve(int l,int r,int l1,int l2){ if(l1>l2)return; if(l==r){ for(int i=l1;i<=l2;++i)ans[q[i]]=l; return; } int mid=l+r>>1; while(now<mid)update(++now,1); while(now>mid)update(now--,-1); int cnt=0; for(int i=l1;i<=l2;++i){ LoveLive p=0; int&id=q[i]; for(int j=0,dd=a[id].size();j<dd&&p<P[id];++j)p+=query(a[id][j]); if(p>=P[id])type[id]=1,++cnt;else type[id]=0; } int t1=l1,t2=l1+cnt; for(int i=l1;i<=l2;++i) if(type[q[i]])tmp[t1++]=q[i];else tmp[t2++]=q[i]; for(int i=l1;i<=l2;++i)q[i]=tmp[i]; solve(l,mid,l1,t1-1); solve(mid+1,r,t1,l2); } int main(){ n=readint(),m=readint(); for(int i=1;i<=m;++i)a[readint()].push_back(i); for(int i=1;i<=n;++i)P[q[i]=i]=readint(); k=readint()+1; for(int i=1;i<k;++i){ d[i].l=readint(); d[i].r=readint(); d[i].s=readint(); } d[k]=(stars){1,m,1e9}; solve(1,k,1,n); for(int i=1;i<=n;++i) if(ans[i]<k)printf("%d ",ans[i]);else puts("NIE"); return 0; }