P4344 [SHOI2015] 腦洞治療儀
說句閒話: 模擬賽因為沒注意push_up痛失70pts
Solution:
感覺比較好寫的線段樹,維護幾個變數:
\(lmx,rmx,mx,cnt\) ,lmx表示該區間從左端點開始的最長連續腦洞的長度,rmx,mx類似.cnt表示該區間內有多少個點是0
然後注意一下push_up:
void push_up(Tree &T,Tree L,Tree R,int l,int r)
{
T.lmx=L.lmx,T.rmx=R.rmx;
if(L.lmx==L.len)T.lmx+=R.lmx;
if(R.rmx==R.len)T.rmx+=L.rmx;
T.mx=max(L.mx,R.mx);
T.mx=max(T.mx,L.rmx+R.lmx);
T.cnt=L.cnt+R.cnt;
T.len=L.len+R.len;
}
由於本人實現比較抽象,所以當push_up需要用來統計答案時,一定要對答案的l,r進行正確的賦值與更新
然後這題就做完了
Code:
#include<bits/stdc++.h>
const int N=2e5+5;
using namespace std;
//Segment_Tree
#define ls x<<1
#define rs x<<1|1
struct Tree{
int lmx,rmx,mx,tag,cnt,len;
}t[N<<2];
void push_up(Tree &T,Tree L,Tree R,int l,int r)
{
T.lmx=L.lmx,T.rmx=R.rmx;
if(L.lmx==L.len)T.lmx+=R.lmx;
if(R.rmx==R.len)T.rmx+=L.rmx;
T.mx=max(L.mx,R.mx);
T.mx=max(T.mx,L.rmx+R.lmx);
T.cnt=L.cnt+R.cnt;
T.len=L.len+R.len;
}
void push_down(int x,int l,int r)
{
if(t[x].tag==-1)return;
int mid=l+r>>1;int len1=mid-l+1,len2=r-(mid+1)+1;
int tag=t[x].tag;
t[ls].cnt=t[ls].lmx=t[ls].mx=t[ls].rmx=len1*tag;
t[rs].cnt=t[rs].lmx=t[rs].mx=t[rs].rmx=len2*tag;
t[ls].tag=t[rs].tag=tag;
//<<"push_down:"<<l<<" "<<r<<" "<<t[x].tag<<"="<<t[ls].cnt<<" "<<t[rs].cnt<<"\n";
t[x].tag=-1;
}
void build(int x,int l,int r)
{
t[x].len=r-l+1;
t[x].cnt=t[x].lmx=t[x].rmx=t[x].mx=0;
t[x].tag=-1;
if(l==r)return;
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
}
void get(int x,int l,int r,int L,int R,int &res)
{
if(L<=l&&r<=R)
{
res+=r-l+1-t[x].cnt;
t[x].cnt=t[x].lmx=t[x].mx=t[x].rmx=r-l+1;
t[x].tag=1;
//<<"get:"<<l<<" "<<r<<"="<<t[x].lmx<<" "<<t[x].rmx<<"=="<<t[x].mx<<" cnt:"<<t[x].cnt<<" tag:"<<t[x].tag<<"\n";
return ;
}
int mid=l+r>>1;
push_down(x,l,r);
if(L<=mid)get(ls,l,mid,L,R,res);
if(mid<R) get(rs,mid+1,r,L,R,res);
push_up(t[x],t[ls],t[rs],l,r);
//<<"get:"<<l<<" "<<r<<"="<<t[x].lmx<<" "<<t[x].rmx<<"=="<<t[x].mx<<" cnt:"<<t[x].cnt<<" tag:"<<t[x].tag<<"\n";
}
void ask(int x,int l,int r,int L,int R,int &res)
{
if(R<L)return ;
//<<"ask:"<<l<<" "<<r<<" "<<L<<" "<<R<<"="<<t[x].cnt<<"\n";
if(L<=l&&r<=R)
{
res+=t[x].cnt;
return;
}
int mid=l+r>>1;
push_down(x,l,r);
if(L<=mid)ask(ls,l,mid,L,R,res);
if(mid<R) ask(rs,mid+1,r,L,R,res);
}
int find(int x,int l,int r,int k)
{
if(l==r)
{
return l;
}
int mid=l+r>>1;
push_down(x,l,r);
if(k>t[ls].cnt) return find(rs,mid+1,r,k-t[ls].cnt);
else return find(ls,l,mid,k);
}
void fix(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
t[x].cnt=t[x].tag=0;
t[x].lmx=t[x].mx=t[x].rmx=0;
return ;
}
int mid=l+r>>1;
push_down(x,l,r);
if(L<=mid)fix(ls,l,mid,L,R);
if(mid<R) fix(rs,mid+1,r,L,R);
push_up(t[x],t[ls],t[rs],l,r);
}
void query(int x,int l,int r,int L,int R,Tree &res)
{
if(L<=l&&r<=R)
{
//<<l<<" "<<r<<"="<<t[x].cnt<<"\n";
push_up(res,res,t[x],l,r);
return;
}
int mid=l+r>>1;
push_down(x,l,r);
if(L<=mid)query(ls,l,mid,L,R,res);
if(mid<R) query(rs,mid+1,r,L,R,res);
}
int n,m;
void work()
{
cin>>n>>m;
build(1,1,n);
for(int i=1,opt,l,r,L,R,k;i<=m;i++)
{
k=0;
scanf("%d%d%d",&opt,&l,&r);
if(opt==0)
{
get(1,1,n,l,r,k);
}
if(opt==1)
{
scanf("%d%d",&L,&R);
get(1,1,n,l,r,k);
int pre=0;
ask(1,1,n,1,L-1,pre);
k+=pre;
if(k==0)continue;
int pos=min(find(1,1,n,k),R);
//<<"fix:"<<pre<<" "<<k-pre<<" "<<pos<<"\n";
fix(1,1,n,L,pos);
}
if(opt==2)
{
Tree ans=(Tree){0,0,0,0,0,0};
query(1,1,n,l,r,ans);
printf("%d\n",ans.mx);
}
}
}
int main()
{
//freopen("instrument.in","r",stdin);
//freopen("instrument.out","w",stdout);
work();
return 0;
}