Description 曾經發明了自動刷題機的發明家SHTSC又公開了他的新發明:腦洞治療儀--一種可以治療他因為發明而日益增大的腦洞的神秘裝置。 為了簡單起見,我們將大腦視作一個01序列。1代表這個位置的腦組織正常工作,0代表這是一塊腦洞。 1 0 1 0 0 0 1 1 1 0 腦洞治療儀修補某一塊腦洞的基本工作原理就是將另一塊連續地區挖出,將其中正常工作的腦組織填補在這塊腦洞中。 (所以腦洞治療儀是腦洞的治療儀。) 例如,用上面第8號位置到第10號位置去修補第1號位置到第4號位置的腦洞。我們就會得到: 1 1 1 1 0 0 1 0 0 0 如果再用第1號位置到第4號位置去修補第8號位置到第10號位置: 0 0 0 0 0 0 1 1 1 1 這是因為腦洞治療儀會把多餘出來的腦組織直接扔掉。 如果再用第7號位置到第10號位置去填補第1號位置到第6號位置: 1 1 1 1 0 0 0 0 0 0 這是因為如果新腦洞挖出來的腦組織不夠多,腦洞治療儀僅會盡量填補位置比較靠前的腦洞。 假定初始時SHTSC並沒有腦洞,給出一些挖腦洞和腦洞治療的操作序列,你需要即時回答SHTSC的問題: 在大腦某個區間中最大的連續腦洞地區有多大。
Input 第一行兩個整數n,m。表示SHTSC的大腦可分為從1到n編號的n個連續地區。有m個操作。 以下m行每行是下列三種格式之一。 0 l r :SHTSC挖了一個從l到r的腦洞。 1 l0 r0 l1 r2 :SHTSC進行了一次腦洞治療,用從l0到r0的腦組織修補l1到r1的腦洞。 2 l r :SHTSC詢問l到r這段區間最大的腦洞有多大。 n,m <=200000,1<=l<=r<=n
Output 對於每個詢問,輸出一行一個整數,表示詢問區間內最大連續腦洞地區有多大。
Sample Input 10 10
0 2 2
0 4 6
0 10 10
2 1 10
1 8 10 1 4
2 1 10
1 1 4 8 10
2 1 10
1 7 10 1 6
2 1 10
Sample Output 3
3
6
6
題解:
線段樹維護區間1的個數,0的個數,區間長度,區間最長連續0,左起最長連續0,右起最長連續0.
這樣可以解決0,2操作。
對於1操作先找到那個區間,然後線上段樹上二分一下即可.
代碼:
#include<iostream>#include<cstdio>#include<cstring>#define N 200010using namespace std;struct use{int s0,s1,sum,len,ls,rs;}t[N<<2];int n,m,k,l,r,ll,rr,p[N<<2],num;int read(){ int x(0); char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } use update(use a,use b){ use c; c.s0=c.s1=c.sum=c.len=c.ls=c.rs=0; c.s0=a.s0+b.s0;c.s1=a.s1+b.s1; c.len=a.len+b.len; c.sum=max(max(a.sum,b.sum),a.rs+b.ls); if (a.s0==a.len) c.ls=a.len+b.ls; else c.ls=a.ls; if (b.s0==b.len) c.rs=b.len+a.rs; else c.rs=b.rs; return c;}void build(int k,int l,int r){ int mid=(l+r)>>1; if (l==r){t[k].s1=t[k].len=1;return;} build(k<<1,l,mid); build(k<<1|1,mid+1,r); t[k]=update(t[k<<1],t[k<<1|1]);}void paint(int k,int l,int r,int v){ if (v==0){ t[k].ls=t[k].rs=t[k].s0=t[k].sum=t[k].len; t[k].s1=0; } if(v==1){ t[k].ls=t[k].rs=t[k].s0=t[k].sum=0; t[k].s1=t[k].len; } p[k]=v;}void pushdown(int k,int l,int r){ int mid=(l+r)>>1; paint(k<<1,l,mid,p[k]); paint(k<<1|1,mid+1,r,p[k]); p[k]=-1; }void change(int k,int l,int r,int ll,int rr,int v){ int mid=(l+r)>>1; if (ll<=l&&r<=rr){paint(k,l,r,v);return;} if (p[k]!=-1) pushdown(k,l,r); if (ll<=mid) change(k<<1,l,mid,ll,rr,v); if (mid<rr) change(k<<1|1,mid+1,r,ll,rr,v); t[k]=update(t[k<<1],t[k<<1|1]); } use query(int k,int l,int r,int ll,int rr){ int mid=(l+r)>>1; if (ll==l&&r==rr) return t[k]; if (p[k]!=-1) pushdown(k,l,r); if (rr<=mid) return query(k<<1,l,mid,ll,rr); else if (mid<ll) return query(k<<1|1,mid+1,r,ll,rr); else return update(query(k<<1,l,mid,ll,mid),query(k<<1|1,mid+1,r,mid+1,rr)); } void find(int k,int l,int r){ int mid=(l+r)>>1; if (t[k].s0<=num){num-=t[k].s0;paint(k,l,r,1);return;} if (p[k]!=-1) pushdown(k,l,r); if (t[k<<1].s0>=num) find(k<<1,l,mid); else{ num-=t[k<<1].s0;paint(k<<1,l,mid,1); find(k<<1|1,mid+1,r); } t[k]=update(t[k<<1],t[k<<1|1]);}void solve(int k,int l,int r,int ll,int rr){ int mid=(l+r)>>1; if (ll<=l&&r<=rr){ if (t[k].s0<=num) num-=t[k].s0,paint(k,l,r,1); else find(k,l,r); return; } if (p[k]!=-1) pushdown(k,l,r); if (ll<=mid&&num) solve(k<<1,l,mid,ll,rr); if (rr>mid&&num) solve(k<<1|1,mid+1,r,ll,rr); t[k]=update(t[k<<1],t[k<<1|1]);}int main(){ n=read();m=read(); for (int i=1;i<=(n<<2);i++) p[i]=-1; build(1,1,n); for (int i=1;i<=m;i++){ k=read(); if (k==0){ l=read();r=read(); change(1,1,n,l,r,0); } if (k==1){ ll=read();rr=read();l=read();r=read(); use t=query(1,1,n,ll,rr); change(1,1,n,ll,rr,0); num=t.s1; solve(1,1,n,l,r); } if (k==2){ l=read();r=read(); use t=query(1,1,n,l,r); printf("%d\n",t.sum); } } }