题意:
有一个星球,它的轨道被划分成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;
}