BZOJ4592:[SHOI2015]脑洞治疗仪(线段树)
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
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
Solution
0操作区间覆盖
2操作是线段树的经典问题,维护一个区间左边连续最大值,右边连续最大值,以及全局最大值,很经典就不多说了
1操作的话我们就统计一下l0,r0之间的1的个数,然后二分在l1,r1间进行区间覆盖就好了
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (200000+1000) 5 using namespace std; 6 7 struct node{int sum,cov,Lmax,Rmax,Mmax,l,r;}Segt[N<<2]; 8 int n,m,opt,l0,r0,l1,r1,Left; 9 10 node operator + (node a,node b) 11 { 12 node c; 13 c.cov=-1; c.l=a.l; c.r=b.r; 14 c.sum=a.sum+b.sum; c.Lmax=a.Lmax; c.Rmax=b.Rmax; 15 if (a.Lmax==a.r-a.l+1) c.Lmax+=b.Lmax; 16 if (b.Rmax==b.r-b.l+1) c.Rmax+=a.Rmax; 17 c.Mmax=max(a.Mmax,b.Mmax); 18 c.Mmax=max(c.Mmax,a.Rmax+b.Lmax); 19 c.Mmax=max(c.Mmax,max(c.Lmax,c.Rmax)); 20 return c; 21 } 22 23 void Build(int now,int l,int r) 24 { 25 Segt[now].cov=-1; Segt[now].l=l; Segt[now].r=r; 26 if (l==r){Segt[now].sum=1; return;} 27 int mid=(l+r)>>1; 28 Build(now<<1,l,mid); Build(now<<1|1,mid+1,r); 29 Segt[now]=Segt[now<<1]+Segt[now<<1|1]; 30 } 31 32 void Pushdown(int now,int l,int r) 33 { 34 if (Segt[now].cov!=-1) 35 { 36 int mid=(l+r)>>1; 37 Segt[now<<1].cov=Segt[now<<1|1].cov=Segt[now].cov; 38 Segt[now<<1].sum=Segt[now].cov*(mid-l+1); 39 Segt[now<<1|1].sum=Segt[now].cov*(r-mid); 40 Segt[now<<1].Lmax=Segt[now<<1].Rmax=Segt[now<<1].Mmax=(Segt[now].cov^1)*(mid-l+1); 41 Segt[now<<1|1].Lmax=Segt[now<<1|1].Rmax=Segt[now<<1|1].Mmax=(Segt[now].cov^1)*(r-mid); 42 Segt[now].cov=-1; 43 } 44 } 45 46 void Update(int now,int l,int r,int l1,int r1,int x) 47 { 48 if (l>r1 || r<l1) return; 49 if (l1<=l && r<=r1) 50 { 51 Segt[now].sum=(r-l+1)*x; 52 Segt[now].cov=x; 53 Segt[now].Lmax=Segt[now].Rmax=Segt[now].Mmax=(r-l+1)*(x^1); 54 return; 55 } 56 Pushdown(now,l,r); 57 int mid=(l+r)>>1; 58 Update(now<<1,l,mid,l1,r1,x); 59 Update(now<<1|1,mid+1,r,l1,r1,x); 60 Segt[now]=Segt[now<<1]+Segt[now<<1|1]; 61 } 62 63 node Query(int now,int l,int r,int l1,int r1) 64 { 65 if (l1<=l && r<=r1) return Segt[now]; 66 Pushdown(now,l,r); 67 int mid=(l+r)>>1; 68 if (mid>=r1) return Query(now<<1,l,mid,l1,r1); 69 if (mid+1<=l1) return Query(now<<1|1,mid+1,r,l1,r1); 70 return Query(now<<1,l,mid,l1,r1)+Query(now<<1|1,mid+1,r,l1,r1); 71 } 72 73 void Change(int now,int l,int r,int l1,int r1) 74 { 75 if (!Left || l>r1 || r<l1) return; 76 if (l1<=l && r<=r1 && Left>=(r-l+1)-Segt[now].sum) 77 { 78 Left-=(r-l+1)-Segt[now].sum; 79 Segt[now].sum=(r-l+1); 80 Segt[now].cov=1; 81 Segt[now].Lmax=Segt[now].Rmax=Segt[now].Mmax=0; 82 return; 83 } 84 Pushdown(now,l,r); 85 int mid=(l+r)>>1; 86 Change(now<<1,l,mid,l1,r1); Change(now<<1|1,mid+1,r,l1,r1); 87 Segt[now]=Segt[now<<1]+Segt[now<<1|1]; 88 } 89 90 int main() 91 { 92 scanf("%d%d",&n,&m); 93 Build(1,1,n); 94 for (int i=1; i<=m; ++i) 95 { 96 scanf("%d",&opt); 97 if (opt==0) 98 { 99 scanf("%d%d",&l0,&r0); 100 Update(1,1,n,l0,r0,0); 101 } 102 if (opt==1) 103 { 104 scanf("%d%d%d%d",&l0,&r0,&l1,&r1); 105 node now1=Query(1,1,n,l0,r0); 106 node now2=Query(1,1,n,l1,r1); 107 Update(1,1,n,l0,r0,0); 108 if (now1.sum>=now2.r-now2.l+1) {Update(1,1,n,l1,r1,1); continue;} 109 Left=now1.sum; Change(1,1,n,l1,r1); 110 } 111 if (opt==2) 112 { 113 scanf("%d%d",&l0,&r0); 114 node now=Query(1,1,n,l0,r0); 115 printf("%d\n",max(now.Mmax,max(now.Rmax,now.Lmax))); 116 } 117 } 118 }