LOJ #2037. 「SHOI2015」脑洞治疗仪
#2037. 「SHOI2015」脑洞治疗仪
题目描述
曾经发明了自动刷题机的发明家 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 的问题:在大脑某个区间中最大的连续脑洞区域有多大。
输入格式
第一行两个整数 n、m,表示 SHTSC 的大脑可分为从 1 到 n 编号的 n 个连续区域,有 m 个操作。
以下 m 行每行是下列三种格式之一:
- 0 l r:SHTSC 挖了一个范围为 [l,r] 的脑洞。
- 1 l0 r0 l1 r1:SHTSC 进行了一次脑洞治疗,用从 l0 到 r0的脑组织修补 l1到 r1的脑洞。
- 2 l r :SHTSC 询问 [l,r]区间内最大的脑洞有多大。
上述区间均在 [1,n] 范围内。
输出格式
对于每个询问,输出一行一个整数,表示询问区间内最大连续脑洞区域有多大。
样例
样例输入
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
样例输出
3
3
6
6
数据范围与提示
对于 20% 的数据,n,m≤100;
对于 50% 的数据,n,m≤20000;
对于 100%的数据,n,m≤200000。
一眼线段树 但是操作太恶心。。。
维护5个域 ml 区间包含左端点最长0串
mr 区间包含右端点最长0串
mx 区间最长0串
sum 区间1的个数 len区间长度(这个不一定要维护 用结构体可以不用写。)
两种 tag 标记 tag=1 区间赋值为1
tag=0 区间赋值为 0
一个是区间赋值为 0 简单的区间修改+标记下放
区间查询 1的个数
区间间从左向右 赋值为1 从每个 0的个数小于当前剩余1个个数的区间填数 每次只将一个小区间填满
区间查询最长0串 这里需要一个辅助变量 因为线段树普通查询只是返回每个区间的最大值
如果我们查询了两个区间 目标区间的最大值恰好是左区间的mr+右区间的ml 这种情况是会出错的
就像 1 1 1 0 0 0 1 一共7个数 要查询 [1,5]的1最大值 线段树查询会先找[1,4] 再找 [5,5] 然后返回 两个区间的最大值
但是 [4,5] 是连续的 所以我们用help变量来记录 每个区间从右端点开始的最大值 与ans比较 再更新
1 #include <cstdio> 2 #include <cctype> 3 4 const int MAXN=200010; 5 6 int n,m,ans,help; 7 8 struct SegmentTree { 9 int l,r; 10 int tag; 11 int mx,ml,mr; 12 int sum,len; 13 }; 14 SegmentTree t[MAXN<<2]; 15 16 inline void read(int&x) { 17 int f=1;register char c=getchar(); 18 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar()); 19 for(;isdigit(c);x=x*10+c-48,c=getchar()); 20 x=x*f; 21 } 22 23 inline int max(int a,int b) {return a<b?b:a;} 24 25 inline void up(int now) { 26 t[now].sum=t[now<<1].sum+t[now*2+1].sum; 27 t[now].mx=max(t[now<<1].mx,t[now*2+1].mx); 28 t[now].ml=t[now<<1].ml; 29 t[now].mr=t[now*2+1].mr; 30 if(t[now<<1].ml==t[now<<1].len) t[now].ml=t[now<<1].len+t[now*2+1].ml; 31 if(t[now*2+1].mr==t[now*2+1].len) t[now].mr=t[now*2+1].len+t[now<<1].mr; 32 t[now].mx=max((max(t[now].ml,t[now].mr),t[now<<1].mr+t[now*2+1].ml),t[now].mx); 33 } 34 35 inline void down(int now) { 36 t[now<<1].tag=t[now<<1|1].tag=t[now].tag; 37 t[now<<1].sum=(t[now<<1].r-t[now<<1].l+1)*t[now].tag; 38 t[now<<1|1].sum=(t[now<<1|1].r-t[now<<1|1].l+1)*t[now].tag; 39 if(t[now].tag) t[now<<1].ml=t[now<<1].mr=t[now<<1].mx=0,t[now<<1|1].ml=t[now<<1|1].mr=t[now<<1|1].mx=0; 40 else t[now<<1].ml=t[now<<1].mr=t[now<<1].mx=t[now<<1].len,t[now<<1|1].ml=t[now<<1|1].mr=t[now<<1|1].mx=t[now<<1|1].len; 41 t[now].tag=-1; 42 } 43 44 void build_tree(int now,int l,int r) { 45 t[now].l=l;t[now].r=r; 46 t[now].len=r-l+1; 47 t[now].tag=-1; 48 if(l==r) { 49 t[now].sum=1; 50 return; 51 } 52 int mid=(l+r)>>1; 53 build_tree(now<<1,l,mid); 54 build_tree(now<<1|1,mid+1,r); 55 t[now].sum=t[now<<1].sum+t[now<<1|1].sum; 56 } 57 58 void modify(int now,int l,int r) { 59 if(l<=t[now].l&&r>=t[now].r) { 60 t[now].tag=0; 61 t[now].sum=0; 62 t[now].ml=t[now].mr=t[now].mx=t[now].len; 63 return; 64 } 65 if(t[now].tag!=-1) down(now); 66 int mid=(t[now].l+t[now].r)>>1; 67 if(l<=mid) modify(now<<1,l,r); 68 if(r>mid) modify(now<<1|1,l,r); 69 up(now); 70 } 71 72 void modify2(int now,int l,int r,int &s) { 73 if(!s) return; 74 if(l<=t[now].l&&r>=t[now].r&&s>=t[now].len-t[now].sum) { 75 s-=t[now].len-t[now].sum; 76 t[now].tag=1; 77 t[now].sum=t[now].len; 78 t[now].mx=t[now].ml=t[now].mr=0; 79 return; 80 } 81 if(t[now].tag!=-1) down(now); 82 int mid=(t[now].l+t[now].r)>>1; 83 if(l<=mid) modify2(now<<1,l,r,s); 84 if(r>mid) modify2(now<<1|1,l,r,s); 85 up(now); 86 } 87 88 void query(int now,int l,int r) { 89 if(l<=t[now].l&&r>=t[now].r) { 90 ans=max(ans,t[now].mx); 91 ans=max(ans,help+t[now].ml); 92 if(t[now].mr==t[now].len) help+=t[now].len; 93 else help=t[now].mr; 94 return; 95 } 96 if(t[now].tag!=-1) down(now); 97 int mid=(t[now].l+t[now].r)>>1; 98 if(l<=mid) query(now<<1,l,r); 99 if(r>mid) query(now<<1|1,l,r); 100 } 101 102 int _query(int now,int l,int r) { 103 int ans=0; 104 if(l<=t[now].l&&r>=t[now].r) return t[now].sum; 105 if(t[now].tag!=-1) down(now); 106 int mid=(t[now].l+t[now].r)>>1; 107 if(l<=mid) ans+=_query(now<<1,l,r); 108 if(r>mid) ans+=_query(now<<1|1,l,r); 109 return ans; 110 } 111 112 int hh() { 113 read(n);read(m); 114 build_tree(1,1,n); 115 for(int type,x,y,L,R,i=1;i<=m;++i) { 116 read(type);read(x);read(y); 117 if(!type) modify(1,x,y); 118 else if(type==2) { 119 ans=0,help=0; 120 query(1,x,y); 121 printf("%d\n",ans); 122 } 123 else { 124 read(L);read(R); 125 int t=_query(1,x,y); 126 modify(1,x,y); 127 modify2(1,L,R,t); 128 } 129 } 130 return 0; 131 } 132 133 int sb=hh(); 134 int main(int argc,char**argv) {;}
作者:乌鸦坐飞机
出处:http://www.cnblogs.com/whistle13326/
新的风暴已经出现
怎么能够停止不前
穿越时空 竭尽全力
我会来到你身边
微笑面对危险
梦想成真不会遥远
鼓起勇气 坚定向前
奇迹一定会出现