[P4344 [SHOI2015] 脑洞治疗仪]
P4344 [SHOI2015] 脑洞治疗仪
说句闲话: 模拟赛因为没注意push_up痛失70pts
Solution:
感觉比较好写的线段树,维护几个变量:
然后注意一下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; }