题意:
有一个星球,它的轨道被划分成m份,由n个国家占领;
一个国家可能占领多个轨道段;
现有q次事件,每次在一个轨道区间上每段落下Ai量的流星雨;
每个国家需要一定量的流星雨,当然它所得的为它占领的轨道段所得之和;
求每个国家所需的东西什么时候可以满足,如果始终不能满足输出NIE;
题解:
这题我第一眼看成了输出TAK或NIE;
结果仔细看看我选择死亡;
边处理事件边判断是否满足答案这个复杂度无论如何都无法接受;
所以要将事件离线下来处理;
另一个思路就是可持久化线段树;
建树的时候只会更改logm个结点,复杂度O(qlogm);
查询二分答案,复杂度O(n*logq*logm);
这样的时间复杂度是可以的啦,然而我们来算算空间;
线段树里要开qlogm个结点,两个long long占16字节;
算一下是80多兆了,似乎实现上就爆掉了?所以这个思路不可行;
我们并不能对时间预处理然后二分,那在二分的过程中处理事件;
只维护一个普通的线段树,那么执行一次二分是O(qlogqlogm)的;
然后复杂度O(nq*logqlogm)这比暴力还挫的复杂度。。
当然不是这样!我们把所有的n一起二分!
每次二分事件区间[l,r],将线段树调整至mid处;
然后统计所有的国家是否满足它的要求;
如果满足,则将其扔到[l,mid]再二分,满足则扔到[mid+1,r];
l==r记录一下答案就好啦!
复杂度O((q+n)logqlogm)?大概就是这么个东西;
好久不写数据结构写写还有点小激动呢2333;
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 310000 #define lson l,mid,no<<1 #define rson mid+1,r,no<<1|1 using namespace std; typedef long long ll; struct node { int no,need,head; }c[N]; int next[N],to[N],ce; int L[N],R[N],a[N]; int n,m,T; ll sum[N<<2],cov[N<<2]; int ans[N]; bool vis[N]; void Pushup(int no) { sum[no]=sum[no<<1]+sum[no<<1|1]; } void Pushdown(int no,int len) { if(cov[no]) { cov[no<<1]+=cov[no]; cov[no<<1|1]+=cov[no]; sum[no<<1]+=cov[no]*(len-(len>>1)); sum[no<<1|1]+=cov[no]*(len>>1); cov[no]=0; } } void update(int l,int r,int no,int st,int en,int val) { if(st<=l&&r<=en) { cov[no]+=val; sum[no]+=(ll)val*(r-l+1); } else { Pushdown(no,r-l+1); int mid=l+r>>1; if(en<=mid) update(lson,st,en,val); else if(st>mid) update(rson,st,en,val); else update(lson,st,en,val),update(rson,st,en,val); Pushup(no); } } ll query(int l,int r,int no,int x) { if(l==r) return sum[no]; else { Pushdown(no,r-l+1); int mid=l+r>>1; if(x<=mid) return query(lson,x); else return query(rson,x); } } void add(int x,int y) { to[++ce]=y; next[ce]=c[x].head; c[x].head=ce; } void slove(int l,int r,int st,int en) { if(st>en) return ; if(l==r) { for(int i=st;i<=en;i++) ans[c[i].no]=l; return ; } int mid=l+r>>1; while(mid>T) { if(L[T+1]<=R[T+1]) update(1,m,1,L[T+1],R[T+1],a[T+1]); else update(1,m,1,L[T+1],m,a[T+1]), update(1,m,1,1,R[T+1],a[T+1]); T++; } while(mid<T) { if(L[T]<=R[T]) update(1,m,1,L[T],R[T],-a[T]); else update(1,m,1,L[T],m,-a[T]), update(1,m,1,1,R[T],-a[T]); T--; } int i,j,cnt; ll temp; for(i=st,cnt=0;i<=en;i++) { for(j=c[i].head,temp=0;j;j=next[j]) { temp+=query(1,m,1,to[j]); if(temp>=c[i].need) break; } if(temp>=c[i].need) vis[i]=1,cnt++; else vis[i]=0; } for(i=st,j=st;i<=en;i++) { if(vis[i]) swap(c[i],c[j++]); } slove(l,mid,st,st+cnt-1); slove(mid+1,r,st+cnt,en); } int main() { int q,i,j,k,x,y; scanf("%d%d",&n,&m); for(i=1;i<=m;i++) scanf("%d",&x),add(x,i); for(i=1;i<=n;i++) scanf("%d",&c[i].need),c[i].no=i; scanf("%d",&q); for(i=1;i<=q;i++) scanf("%d%d%d",L+i,R+i,a+i); q++; L[q]=1,R[q]=m,a[q]=1e9; slove(1,q,1,n); for(i=1;i<=n;i++) if(ans[i]!=q) printf("%d\n",ans[i]); else puts("NIE"); return 0; }