4592: [Shoi2015]脑洞治疗仪
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 338 Solved: 142
[ Submit][ Status][ Discuss]
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
3
6
6
HINT
Source
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 2E5 + 20;
const int T = 4;
int n,m,tp,Ans,cnt[maxn*T][2],Max[maxn*T],Left[maxn*T],Right[maxn*T],Mark[maxn*T],stk[30];
bool All[maxn*T];
void Build(int o,int l,int r)
{
Mark[o] = -1; cnt[o][1] = r - l + 1;
if (l == r) return; int mid = l + r >> 1;
Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
}
void pushdown(int o,int l,int r)
{
if (Mark[o] == -1) return;
if (Mark[o])
{
cnt[o][1] = r - l + 1; All[o] = 0;
cnt[o][0] = Left[o] = Right[o] = Max[o] = 0;
}
else
{
cnt[o][1] = 0; All[o] = 1;
cnt[o][0] = Left[o] = Right[o] = Max[o] = r - l + 1;
}
if (l == r) {Mark[o] = -1; return;}
Mark[o<<1] = Mark[o<<1|1] = Mark[o]; Mark[o] = -1;
}
void maintain(int o)
{
int lc = (o<<1),rc = (o<<1|1);
cnt[o][0] = cnt[lc][0] + cnt[rc][0];
cnt[o][1] = cnt[lc][1] + cnt[rc][1];
All[o] = All[lc] && All[rc] ? 1 : 0;
Left[o] = All[lc] ? Max[lc] + Left[rc] : Left[lc];
Right[o] = All[rc] ? Max[rc] + Right[lc] : Right[rc];
Max[o] = max(Max[lc],Max[rc]); Max[o] = max(Max[o],Right[lc] + Left[rc]);
}
int Cover_0(int o,int l,int r,int ql,int qr)
{
pushdown(o,l,r);
if (ql <= l && r <= qr)
{
int ret = cnt[o][1];
Mark[o] = 0; pushdown(o,l,r);
return ret;
}
int ret = 0,mid = l + r >> 1;
if (ql <= mid) ret = Cover_0(o<<1,l,mid,ql,qr); else pushdown(o<<1,l,mid);
if (qr > mid) ret += Cover_0(o<<1|1,mid+1,r,ql,qr); else pushdown(o<<1|1,mid+1,r);
maintain(o); return ret;
}
void Cover_1(int o,int l,int r,int ql,int qr,int &res)
{
int mid = l + r >> 1; pushdown(o,l,r);
if (ql <= l && r <= qr)
{
if (cnt[o][0] <= res)
{
res -= cnt[o][0]; Mark[o] = 1;
pushdown(o,l,r); return;
}
int mid = l + r >> 1;
if (res) Cover_1(o<<1,l,mid,ql,qr,res); else pushdown(o<<1,l,mid);
if (res) Cover_1(o<<1|1,mid+1,r,ql,qr,res); else pushdown(o<<1|1,mid+1,r);
maintain(o);
}
if (ql <= mid && res) Cover_1(o<<1,l,mid,ql,qr,res); else pushdown(o<<1,l,mid);
if (qr > mid && res) Cover_1(o<<1|1,mid+1,r,ql,qr,res); else pushdown(o<<1|1,mid+1,r);
maintain(o);
}
void GetRange(int o,int l,int r,int ql,int qr)
{
pushdown(o,l,r);
if (ql <= l && r <= qr)
{Ans = max(Ans,Max[o]); stk[++tp] = o; return;}
int mid = l + r >> 1;
if (ql <= mid) GetRange(o<<1,l,mid,ql,qr);
if (qr > mid) GetRange(o<<1|1,mid+1,r,ql,qr);
}
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint(); m = getint(); Build(1,1,n);
while (m--)
{
int typ = getint(),l,r;
l = getint(); r = getint();
if (!typ) Cover_0(1,1,n,l,r);
else if (typ == 1)
{
int ret = Cover_0(1,1,n,l,r);
l = getint(); r = getint();
if (ret) Cover_1(1,1,n,l,r,ret);
}
else
{
tp = Ans = 0;
GetRange(1,1,n,l,r); stk[tp + 1] = 0;
for (int i = 1; i <= tp; i++)
{
Ans = max(Ans,Right[stk[i - 1]] + Left[stk[i]]);
if (!All[stk[i]] || All[stk[i - 1]]) continue;
int now = Right[stk[i - 1]];
for (int j = i; j <= tp; j++)
if (All[stk[j]]) now += Max[stk[j]];
else {now += Left[stk[j]]; break;}
Ans = max(Ans,now);
}
printf("%d\n",Ans);
}
}
return 0;
}