题解[SHOI2015]脑洞治疗仪
Posted Refined_heart
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解[SHOI2015]脑洞治疗仪相关的知识,希望对你有一定的参考价值。
\\(\\text{Solution:}\\)
这题唯一需要学习 or 复习的点就是它的查询了。
这东西一眼的维护左右最长连续的 \\(0\\) 的长度就做完了。标记什么的都很简单。代码量略微大一点。
注意在询问的时候:
如果完全在左右区间,就分别递归。
否则,我们还需要考虑跨越区间的最值。那应该是:从当前向左右两侧延申最长距离之和。
这个自己推一下就行了。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+10;
int ls[MAXN],rs[MAXN],sum[MAXN];
int node,opt;
int llen[MAXN],rlen[MAXN],mlen[MAXN];
int L[MAXN],R[MAXN],tag[MAXN],n,m,rt;
inline int read() {
int s=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) {
s=s*10-48+ch;
ch=getchar();
}
return s;
}
inline int Len(int x) {
return R[x]-L[x]+1;
}
inline int Min(int x,int y) {
return x<y?x:y;
}
inline int Max(int x,int y) {
return x>y?x:y;
}
inline void pushup(int x) {
sum[x]=sum[ls[x]]+sum[rs[x]];
llen[x]=llen[ls[x]];
if(llen[ls[x]]==Len(ls[x]))
llen[x]+=llen[rs[x]];
rlen[x]=rlen[rs[x]];
if(rlen[x]==Len(rs[x]))
rlen[x]+=rlen[ls[x]];
mlen [ x ] = Max ( mlen [ ls [ x ] ] , mlen [ rs [ x ] ] ) ;
mlen [ x ] = Max ( mlen [ x ] , rlen [ ls [ x ] ] + llen [ rs [ x ] ] ) ;
}
void build(int &x,int l,int r) {
if(!x)x=++node;
L[x]=l;
R[x]=r;
tag[x]=-1;
if(l==r) {
rlen[x]=llen[x]=mlen[x]=0;
sum[x]=1;
return;
}
int mid=(l+r)>>1;
build(ls[x],l,mid);
build(rs[x],mid+1,r);
pushup(x);
}
inline void pushdown(int x) {
if(tag[x]!=-1) {
int p=tag[x];
tag[x]=-1;
tag[ls[x]]=tag[rs[x]]=p;
sum[ls[x]]=p*Len(ls[x]);
sum[rs[x]]=p*Len(rs[x]);
if(p==0) {
llen[ls[x]]=rlen[ls[x]]=mlen[ls[x]]=Len(ls[x]);
llen[rs[x]]=rlen[rs[x]]=mlen[rs[x]]=Len(rs[x]);
} else {
llen[ls[x]]=rlen[ls[x]]=mlen[ls[x]]=0;
llen[rs[x]]=rlen[rs[x]]=mlen[rs[x]]=0;
}
}
}
int query(int x,int l,int r) {
if(L[x]>=l&&R[x]<=r)return sum[x];
pushdown(x);
int mid=(L[x]+R[x])>>1,res=0;
if(l<=mid)res=query(ls[x],l,r);
if(mid<r)res+=query(rs[x],l,r);
pushup(x);
return res;
}
void change(int x,int l,int r,int v) {
if(L[x]>=l&&R[x]<=r) {
tag[x]=v;
sum[x]=v*Len(x);
llen[x]=rlen[x]=mlen[x]=(1-v)*Len(x);
return;
}
pushdown(x);
int mid=(L[x]+R[x])>>1;
if(l<=mid)change(ls[x],l,r,v);
if(mid<r)change(rs[x],l,r,v);
pushup(x);
}
int query_max(int x,int l,int r) {
if(L[x]>=l&&R[x]<=r)return mlen[x];
pushdown(x);
int mid=(L[x]+R[x])>>1;
if(r<=mid)return query_max(ls[x],l,r);
else if(l>mid)return query_max(rs[x],l,r);
return Max(Max(query_max(ls[x],l,r),query_max(rs[x],l,r)),Min(rlen[ls[x]],L[rs[x]]-l)+Min(llen[rs[x]],r-R[ls[x]]));
}
int querypos(int l,int r,int s) {
int L=l,R=r,ans=l;
while(L<=R){
int mid=(L+R)>>1;
if(mid-l+1-(query(rt,l,mid))<=s)ans=mid,L=mid+1;
else R=mid-1;
}
return ans;
}
//void dfs(int x){
// pushdown(x);
// if(!ls[x]&&!rs[x])printf("%d ",sum[x]);
// if(ls[x])dfs(ls[x]);
// if(rs[x])dfs(rs[x]);
//}
inline void write(int x){
if(x>9)write(x/10);
putchar(x%10+48);
}
int main() {
n=read();
m=read();
build(rt,1,n);
while(m--) {
opt=read();
int al=read(),ar=read(),bl,br;
if(opt==0)change(rt,al,ar,0);
else if(opt==1) {
bl=read();
br=read();
int S=query(rt,al,ar);
change(rt,al,ar,0);
int P=query(rt,bl,br);
int cnt0=(br-bl+1)-P;
S=Min(S,cnt0);
if(S==0)continue;
int pos=querypos(bl,br,S);
change(rt,bl,pos,1);
} else write(query_max(rt,al,ar)),putchar(\'\\n\');
}
return 0;
}
以上是关于题解[SHOI2015]脑洞治疗仪的主要内容,如果未能解决你的问题,请参考以下文章