题解:P2894 [USACO08FEB] Hotel G
给一个分块做法。
对于每个块,分别维护这个块前缀 / 后缀连续空房的个数和块内最大的连续空房长度。
对于修改操作,散块直接暴力重构,整块则打上标记,顺便更新一下这个块维护的值。
对于查询操作,直接遍历每个块求出答案,如果答案在一个块里面就遍历这个块找到答案,否则,答案一定是由一段后缀 + 若干个整块 + 一段前缀组成,在遍历时顺便求出即可。
时间复杂度
代码:
#include<bits/stdc++.h>
using namespace std;
const int len=223;
int a[50010],bel[50010],L[310],R[310],lmx[310],rmx[310],mx[310],tag[310],n,q;
void pushtag(int x){
if(tag[x]==-1)return;
if(tag[x]==1){
for(int i=L[x];i<=R[x];i++)a[i]=1;
lmx[x]=rmx[x]=mx[x]=0,tag[x]=-1;
return;
}
for(int i=L[x];i<=R[x];i++)a[i]=0;
lmx[x]=rmx[x]=mx[x]=R[x]-L[x]+1,tag[x]=-1;
return;
}
void pushup(int x){
lmx[x]=rmx[x]=0;
for(int i=L[x];i<=R[x];i++){
if(a[i])break;
lmx[x]++;
}
for(int i=R[x];i>=L[x];i--){
if(a[i])break;
rmx[x]++;
}
mx[x]=max(lmx[x],rmx[x]);
int cnt=0;
for(int i=L[x]+lmx[x]+1;i<=R[x]-rmx[x];i++)cnt=(a[i]?0:cnt+1),mx[x]=max(mx[x],cnt);
return;
}
void update(int x,int y){
pushtag(bel[x]),pushtag(bel[y]);
if(bel[x]==bel[y]){
for(int i=x;i<=y;i++)a[i]=1;
pushup(bel[x]);
return;
}
for(int i=x;i<=R[bel[x]];i++)a[i]=1;
for(int i=L[bel[y]];i<=y;i++)a[i]=1;
pushup(bel[x]),pushup(bel[y]);
for(int i=bel[x]+1;i<bel[y];i++){
lmx[i]=rmx[i]=mx[i]=0,tag[i]=1;
}
return;
}
void update2(int x,int y){
pushtag(bel[x]),pushtag(bel[y]);
if(bel[x]==bel[y]){
for(int i=x;i<=y;i++)a[i]=0;
pushup(bel[x]);
return;
}
for(int i=x;i<=R[bel[x]];i++)a[i]=0;
for(int i=L[bel[y]];i<=y;i++)a[i]=0;
pushup(bel[x]),pushup(bel[y]);
for(int i=bel[x]+1;i<bel[y];i++){
lmx[i]=rmx[i]=mx[i]=R[i]-L[i]+1,tag[i]=0;
}
return;
}
int qry(int x,int y){
int cnt=0,pos=L[x];
for(int i=L[x];i<=R[x];i++){
if(a[i])cnt=0,pos=i;
else cnt++;
if(cnt>=y)return pos+1;
}
return 0;
}
int query(int x){
int ans=0,p=1;
for(int i=1;i<=bel[n];i++){
if(mx[i]==R[i]-L[i]+1){
ans+=mx[i];
if(ans>=x)return p;
}else{
ans+=lmx[i];
if(ans>=x)return p;
if(mx[i]>=x)return qry(i,x);
p=R[i]-rmx[i]+1,ans=rmx[i];
if(ans>=x)return p;
}
}
return 0;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++)bel[i]=(i-1)/len+1;
for(int i=1;i<=bel[n];i++){
L[i]=(i-1)*len+1,R[i]=min(i*len,n);
lmx[i]=rmx[i]=mx[i]=R[i]-L[i]+1,tag[i]=-1;
}
for(int i=1;i<=q;i++){
int op,x,y;
cin>>op>>x;
if(op==1){
int tmp=query(x);
cout<<tmp<<'\n';
if(tmp)update(tmp,tmp+x-1);
}else cin>>y,update2(x,x+y-1);
}
return 0;
}