SHOI2015 脑洞治疗仪
题目链接:戳我
luogu的题面真心好看!!!qwqwq
按照专业的话来讲,这个题是——线段树维护最大连续子段
好吧。。其实就和前两天写的那个区间最大字段和很相似嘛,就是左右线段树可以合并这种维护信息类型的题目。
操作0是线段树区间赋值
操作1是线段树区间赋值+线段树区间前K个赋值(前K个怎么实现呢?就是我们在线段树上直接二分,然后找到那些0的个数小于等于K的区间们,然后一个一个依次赋值)
操作2是求线段树中最大相同子段长度
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define MAXN 200010
using namespace std;
int n,m;
int le[MAXN<<2],ri[MAXN<<2];
struct Node{int maxl,maxr,maxs,sum0,sum1,tag;}t[MAXN<<2];
inline int ls(int x){return x<<1;}
inline int rs(int x){return x<<1|1;}
inline void update(int x,int k)
{
if(k==0)
{
t[x].sum0=t[x].maxl=t[x].maxr=t[x].maxs=ri[x]-le[x]+1;
t[x].sum1=0;
}
else if(k==1)
{
t[x].sum1=ri[x]-le[x]+1;
t[x].sum0=t[x].maxl=t[x].maxr=t[x].maxs=0;
}
t[x].tag=k;
}
inline void push_up(int x)
{
t[x].sum0=t[ls(x)].sum0+t[rs(x)].sum0;
t[x].sum1=t[ls(x)].sum1+t[rs(x)].sum1;
t[x].maxl=t[ls(x)].maxl;
if(t[ls(x)].maxl==ri[ls(x)]-le[ls(x)]+1) t[x].maxl=max(t[x].maxl,t[ls(x)].maxl+t[rs(x)].maxl);
t[x].maxr=t[rs(x)].maxr;
if(t[rs(x)].maxr==ri[rs(x)]-le[rs(x)]+1) t[x].maxr=max(t[x].maxr,t[rs(x)].maxr+t[ls(x)].maxr);
t[x].maxs=max(max(t[ls(x)].maxs,t[rs(x)].maxs),t[ls(x)].maxr+t[rs(x)].maxl);
}
inline void push_down(int x)
{
if(t[x].tag!=-1)
{
update(ls(x),t[x].tag);
update(rs(x),t[x].tag);
t[x].tag=-1;
}
}
inline void build(int x,int l,int r)
{
t[x].tag=-1;
le[x]=l; ri[x]=r;
if(le[x]==ri[x]){t[x].sum1=1;return;}
int mid=(le[x]+ri[x])>>1;
build(ls(x),le[x],mid);
build(rs(x),mid+1,ri[x]);
push_up(x);
}
inline void clean(int x,int ll,int rr)
{
if(ll==le[x]&&ri[x]==rr) {update(x,0);return;}
int mid=(le[x]+ri[x])>>1;
push_down(x);
if(rr<=mid) clean(ls(x),ll,rr);
else if(mid<ll) clean(rs(x),ll,rr);
else clean(ls(x),ll,mid),clean(rs(x),mid+1,rr);
push_up(x);
}
inline int que_sum(int x,int ll,int rr)
{
if(ll==le[x]&&ri[x]==rr) return t[x].sum1;
int mid=(le[x]+ri[x])>>1;
push_down(x);
if(rr<=mid) return que_sum(ls(x),ll,rr);
else if(mid<ll) return que_sum(rs(x),ll,rr);
else return que_sum(ls(x),ll,mid)+que_sum(rs(x),mid+1,rr);
}
inline int query(int x,int ll,int rr)
{
if(ll==le[x]&&ri[x]==rr) return t[x].maxs;
int mid=(le[x]+ri[x])>>1;
push_down(x);
if(rr<=mid) return query(ls(x),ll,rr);
else if(mid<ll) return query(rs(x),ll,rr);
else
{
int cur1=query(ls(x),ll,mid);
int cur2=query(rs(x),mid+1,rr);
int z1=min(t[ls(x)].maxr,mid-ll+1);
int z2=min(t[rs(x)].maxl,rr-mid);
return max(max(cur1,cur2),z1+z2);
}
}
inline void mend(int x,int ll,int rr,int &k)
{
if(k<=0) return;
if(ll==le[x]&&ri[x]==rr&&k>=t[x].sum0)
{
k-=t[x].sum0;
update(x,1);
return;
}
int mid=(le[x]+ri[x])>>1;
push_down(x);
if(rr<=mid) mend(ls(x),ll,rr,k);
else if(mid<ll) mend(rs(x),ll,rr,k);
else
{
mend(ls(x),ll,mid,k);
if(k>=0) mend(rs(x),mid+1,rr,k);
else k=0;
}
push_up(x);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int op,l,r,ll,rr;
scanf("%d",&op);
if(op==0)
{
scanf("%d%d",&l,&r);
clean(1,l,r);
}
else if(op==1)
{
scanf("%d%d%d%d",&l,&r,&ll,&rr);
int k=que_sum(1,l,r);
clean(1,l,r);
mend(1,ll,rr,k);
}
else
{
scanf("%d%d",&l,&r);
printf("%d\n",query(1,l,r));
}
}
return 0;
}
不过我写的原先不是把l,r写在struct里面的那种写法,是直接跟在函数里面的。但是之后发现。。。。不知道为什么它的左右区间不对应。。。之后就重构了一遍写了这种写法。。。。菜是原罪。。整天都是莫名其妙的锅qwqwq