【SHOI2015】腦洞治療儀(惡心的線段樹,區間最大子段和)
題目描述:
曾經發明了自動刷題機的發明家 SHTSC 又公開了他的新發明:腦洞治療儀——一種可以治療他因為發明而日益增大的腦洞的神秘裝置。
為了簡單起見,我們將大腦視作一個 01 序列。11代表這個位置的腦組織正常工作,00代表這是一塊腦洞。
1 0 1 0 0 0 1 1 1 0
腦洞治療儀修補某一塊腦洞的基本工作原理就是將另一塊連續區域挖出,將其中正常工作的腦組織填補在這塊腦洞中。(所以腦洞治療儀是腦洞的治療儀?)
例如,用上面第88號位置到第1010號位置去修補第11號位置到第44號位置的腦洞,我們就會得到:
1 1 1 1 0 0 1 0 0 0
如果再用第11號位置到第44號位置去修補第88號位置到第1010號位置:
0 0 0 0 0 0 1 1 1 1
這是因為腦洞治療儀會把多余出來的腦組織直接扔掉。
如果再用第77號位置到第1010號位置去填補第11號位置到第66號位置:
1 1 1 1 0 0 0 0 0 0
這是因為如果新腦洞挖出來的腦組織不夠多,腦洞治療儀僅會盡量填補位置比較靠前的腦洞。
假定初始時 SHTSC 並沒有腦洞,給出一些挖腦洞和腦洞治療的操作序列,你需要即時回答 SHTSC 的問題:在大腦某個區間中最大的連續腦洞區域有多大。
輸入輸出格式
輸入格式:
第一行兩個整數 n、m,表示 SHTSC 的大腦可分為從1到n編號的n個連續區域,有m個操作。
以下m行每行是下列三種格式之一:
0 l r:SHTSC 挖了一個範圍為[l,r]的腦洞。
1 $l_0$ $r_0$ $l_1$ $r_1$:SHTSC 進行了一次腦洞治療,用從$l_0$ 到$r_0$ 的腦組織修補$l_1$到$r_1$ 的腦洞。
2 $l$ $r$:SHTSC 詢問$[l,r]$區間內最大的腦洞有多大。
上述區間均在$[1,n]$範圍內。
輸出格式:
對於每個詢問,輸出一行一個整數,表示詢問區間內最大連續腦洞區域有多大。
思路
很多題解都提到了GSS系列的最大連續子段和問題,那我就不說了,我只說這道題中我用到的一些奇妙的解法
1.反著定義
這道題要求的是最大連續0的長度,那麽用最大子段和的話如果你按1走統計的就不是0,而是1,我們可以將1定義為-inf,0定義為1,再跑最大子段和即可
2.分開存
gss中要存一個區間和sum,但由於上面的定義形式,這玩意兒顯然不能表示0(或1)的數量,我們可以用一個mix,專門存0或1的數量
大體思路:
0.首先,給1節點打上-inf的lazy標記,表示沒有腦洞
1.對於0操作,區間覆蓋,打lazy標記後直接修改即可
2.對於2操作,GSS標準查詢即可
3.對於1操作,先求出l1,r1的腦組織數,再全挖成腦洞,之後填進l2,r2去即可(函數寫成int式,優先填左區間,填完後返回剩余腦洞數)
代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define rii register int i #define rij register int j #define rs 262144 #define int long long using namespace std; struct tree{ long long lmax,rmax,sum,lazy,maxn,mix; }x[1000005]; int n,m,p; void pushdown(int nl,int nr,long long val,int bh) { int mid=(nl+nr)/2; long long cd=mid-nl+1; x[bh*2].lazy=val; x[bh*2].lmax=val*cd; x[bh*2].rmax=val*cd; x[bh*2].sum=val*cd; x[bh*2].maxn=val*cd; x[bh*2].mix=(val%2)*cd; x[bh*2+1].mix=(val%2)*cd; x[bh*2+1].lazy=val; x[bh*2+1].lmax=val*cd; x[bh*2+1].rmax=val*cd; x[bh*2+1].sum=val*cd; x[bh*2+1].maxn=val*cd; x[bh].lazy=0; } void fg(int l,int r,int nl,int nr,int bh) { if(l<nl) { l=nl; } if(r>nr) { r=nr; } if(x[bh].lazy==1) { return; } if(x[bh].lazy==-100000) { pushdown(nl,nr,x[bh].lazy,bh); } if(l==nl&&r==nr) { x[bh].lazy=1; x[bh].sum=(r-l+1); x[bh].lmax=(r-l+1); x[bh].rmax=(r-l+1); x[bh].maxn=(r-l+1); x[bh].mix=(r-l+1); return; } int mid=(nl+nr)/2; if(l<=mid) { fg(l,r,nl,mid,bh*2); } if(r>=mid+1) { fg(l,r,mid+1,nr,bh*2+1); } x[bh].mix=x[bh*2].mix+x[bh*2+1].mix; x[bh].sum=x[bh*2].sum+x[bh*2+1].sum; x[bh].lmax=max(x[bh*2].lmax,x[bh*2].sum+x[bh*2+1].lmax); x[bh].rmax=max(x[bh*2+1].rmax,x[bh*2+1].sum+x[bh*2].rmax); x[bh].maxn=max(x[bh*2].maxn,max(x[bh*2+1].maxn,x[bh*2].rmax+x[bh*2+1].lmax)); } int sum(int l,int r,int nl,int nr,int bh) { if(l<nl) { l=nl; } if(r>nr) { r=nr; } if(l==nl&&r==nr) { return x[bh].mix; } if(x[bh].lazy!=0&&nl!=nr) { pushdown(nl,nr,x[bh].lazy,bh); } int mid=(nl+nr)/2; int ans=0; if(l<=mid) { ans+=sum(l,r,nl,mid,bh*2); } if(r>=mid+1) { ans+=sum(l,r,mid+1,nr,bh*2+1); } return ans; } int add(int l,int r,int nl,int nr,int sl,int bh) { if(l<nl) { l=nl; } if(r>nr) { r=nr; } if(x[bh].lazy!=0) { pushdown(nl,nr,x[bh].lazy,bh); } if(l==nl&&r==nr&&sl>=(r-l+1)) { sl-=x[bh].mix; x[bh].mix=0; x[bh].lmax=(-100000)*(r-l+1); x[bh].rmax=(-100000)*(r-l+1); x[bh].maxn=(-100000)*(r-l+1); x[bh].sum=(-100000)*(r-l+1); x[bh].lazy=-100000; return sl; } int mid=(nl+nr)/2; if(l<=mid&&sl!=0) { sl=add(l,r,nl,mid,sl,bh*2); } if(r>=mid+1&&sl!=0) { sl=add(l,r,mid+1,nr,sl,bh*2+1); } x[bh].mix=x[bh*2].mix+x[bh*2+1].mix; x[bh].sum=x[bh*2].sum+x[bh*2+1].sum; x[bh].lmax=max(x[bh*2].lmax,x[bh*2].sum+x[bh*2+1].lmax); x[bh].rmax=max(x[bh*2+1].rmax,x[bh*2+1].sum+x[bh*2].rmax); x[bh].maxn=max(x[bh*2].maxn,max(x[bh*2+1].maxn,x[bh*2].rmax+x[bh*2+1].lmax)); return sl; } tree query(int l,int r,int nl,int nr,int bh) { tree an,bn; if(l<nl) { l=nl; } if(r>nr) { r=nr; } if(x[bh].lazy!=0) { pushdown(nl,nr,x[bh].lazy,bh); } if(nl==l&&nr==r) { an=x[bh]; return an; } int ltt=(nl+nr)/2; if(l<=ltt&&r<=ltt) { return an=query(l,r,nl,ltt,bh*2); } if(r>ltt&&l>ltt) { return bn=query(l,r,ltt+1,nr,bh*2+1); } else { an=query(l,r,nl,ltt,bh*2); bn=query(l,r,ltt+1,nr,bh*2+1); an.maxn=max(an.maxn,max(bn.maxn,an.rmax+bn.lmax)); an.lmax=max(an.lmax,an.sum+bn.lmax); an.rmax=max(bn.rmax,bn.sum+an.rmax); an.sum=an.sum+bn.sum; return an; } } signed main() { // freopen("1.in","r",stdin); // freopen("1.out","w",stdout); scanf("%lld%lld",&n,&m); x[1].lazy=-100000; for(rii=1;i<=m;i++) { int l,r; scanf("%lld",&p); if(p==0) { scanf("%lld%lld",&l,&r); fg(l,r,1,rs,1); } if(p==2) { scanf("%lld%lld",&l,&r); tree ans=query(l,r,1,rs,1); if(ans.maxn<0) { ans.maxn=0; } printf("%lld\n",ans.maxn); } if(p==1) { int l1,l2,r1,r2; scanf("%lld%lld%lld%lld",&l2,&r2,&l1,&r1); int ltt=sum(l2,r2,1,rs,1); ltt=(r2-l2+1)-ltt; fg(l2,r2,1,rs,1); if(ltt>(r2-l2+1)) { ltt=r2-l2+1; } add(l1,r1,1,rs,ltt,1); } } }
【SHOI2015】腦洞治療儀(惡心的線段樹,區間最大子段和)