luogu P3527 [POI2011]MET-Meteors
此题可以使用整体二分解决。
我们发现把所有国家收集陨石的情况都查一遍的总复杂度是固定的,那么这时候我们就可以放心的使用整体二分:
-
记\(solve(l,r,x,y)\)表示\([x,y]\)这些国家,他们的答案范围在\([l,r]\)内,并设\(mid\) 为\([l,r]\)的中点
-
我们先把\([l,mid]\)范围内的陨石落下,再对每个国家查询:若此国家已经收集够陨石,则他们所属答案区间为\([l,mid]\),否则更新此国家的需要陨石的数目,然后把它放进\([mid+1,r]\)中
分析时间复杂度(重点):我们可以类比线段树的把我们的分支结构看成\(O(logn)\)层,然后我们发现对于国家查询,每层的复杂度相同(因为每层都会把所有国家查一遍),由于使用树状数组,所以每层均摊复杂度\(O(nlogn)\),一共\(O(log)\)层,所以总复杂度为\(O(nlog^2n)\)。
代码:
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;
const int N=300009;
int n,m,L[N],R[N],A[N],k,ans[N],f;
LL c[N];
struct Edge
{
int nxt,to;
}b[N*2];
struct Question
{
LL need;
int head,id;
}q[N],q_[N],Q_[N];
void Add(int from,int to)
{
b[++f].nxt=q[from].head;
b[f].to=to;
q[from].head=f;
}
inline void add(int x,LL v)
{
while(x<=m)
{
c[x]+=v;
x+=x&(-x);
}
}
inline LL getsum(int x)
{
LL ans=0;
while(x)
{
ans+=c[x];
x-=x&(-x);
}
return ans;
}
inline int read()
{
int x=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
x=x*10+c-'0',c=getchar();
return x;
}
void init()
{
n=read(),m=read();
for (int i=1,x;i<=m;i++)
x=read(),Add(x,i);
for (int i=1;i<=n;i++)
q[i].need=read(),q[i].id=i;
k=read();
for (int i=1;i<=k;i++)
L[i]=read(),R[i]=read(),A[i]=read();
}
inline void Modify(int x,int y,LL v)
{
add(x,v),add(y+1,-v);
}
inline LL Query(int x)
{
return getsum(x);
}
inline void solve(int l,int r,int x,int y)
{
if(l==r)
{
for (int i=x;i<=y;i++)
ans[q[i].id]=l;
return;
}
int mid=l+r>>1;
for (int i=l;i<=mid;i++)
if(L[i]<=R[i])
Modify(L[i],R[i],A[i]);
else
Modify(L[i],m,A[i]),Modify(1,R[i],A[i]);
int cnt=0,cnt_=0;
for (int i=x;i<=y;i++)
{
int flag=0,j;
for (j=q[i].head;j;j=b[j].nxt)
{
int v=b[j].to;
LL Q=Query(v);
if(q[i].need<=Q)
{
flag=1;
break;
}
q[i].need-=Q;
}
if(flag)
{
for (int k=q[i].head;k!=j;k=b[k].nxt)
q[i].need+=Query(b[k
].to);
q_[++cnt]=q[i];
}
else
Q_[++cnt_]=q[i];
}
for (int i=l;i<=mid;i++)
if(L[i]<=R[i])
Modify(L[i],R[i],-A[i]);
else
Modify(L[i],m,-A[i]),Modify(1,R[i],-A[i]);
int i=x;
for (int j=1;j<=cnt;j++,i++)
q[i]=q_[j];
for (int j=1;j<=cnt_;i++,j++)
q[i]=Q_[j];
if(cnt)
solve(l,mid,x,x+cnt-1);
if(cnt_)
solve(mid+1,r,x+cnt,y);
}
void work()
{
solve(1,k+1,1,n);
for (int i=1;i<=n;i++)
if(ans[i]==k+1)
puts("NIE");
else
printf("%d\n",ans[i]);
}
int main()
{
init();
work();
return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!