曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置。
为了简单起见,我们将大脑视作一个 01 序列。 1 1 1 代表这个位置的脑组织正常工作, 0 0 0 代表这是一块脑洞。
1 0 1 0 0 0 1 1 1 0
脑洞治疗仪修补某一块脑洞的基本工作原理就是将另一块连续区域挖出,将其中正常工作的脑组织填补在这块脑洞中。(所以脑洞治疗仪是脑洞的治疗仪?)
例如,用上面第 8 8 8 号位置到第 10 10 10 号位置去修补第 1 1 1 号位置到第 4 4 4 号位置的脑洞,我们就会得到:
1 1 1 1 0 0 1 0 0 0
如果再用第 1 1 1 号位置到第 4 4 4 号位置去修补第 8 8 8 号位置到第 10 10 10 号位置:
0 0 0 0 0 0 1 1 1 1
这是因为脑洞治疗仪会把多余出来的脑组织直接扔掉。
如果再用第 7 7 7 号位置到第 10 10 10 号位置去填补第 1 1 1 号位置到第 6 6 6 号位置:
1 1 1 1 0 0 0 0 0 0
这是因为如果新脑洞挖出来的脑组织不够多,脑洞治疗仪仅会尽量填补位置比较靠前的脑洞。
假定初始时 SHTSC 并没有脑洞,给出一些挖脑洞和脑洞治疗的操作序列,你需要即时回答 SHTSC 的问题:在大脑某个区间中最大的连续脑洞区域有多大。
第一行两个整数 n , m n,m n,m,表示 SHTSC 的大脑可分为从 1 1 1 到 n n n 编号的 n n n 个连续区域,有 m m m 个操作。
以下 m m m 行每行是下列三种格式之一:
上述区间均在 [ 1 , n ] [1, n] [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 % 20\% 20% 的数据, n , m ≤ 100 n, m \leq 100 n,m≤100;
对于 50 % 50\% 50% 的数据, n , m ≤ 20000 n, m \leq 20000 n,m≤20000;
对于 100 % 100\% 100% 的数据, n , m ≤ 200000 n, m \leq 200000 n,m≤200000。
给定一个 1 序列,有三种操作:
因为询问是最长连续 0 的长度,所以可以考虑使用线段树来维护
对于操作一,线段树可以实现。
对于操作二,可以分为两步:
因为是从左到右填充,所以需要确定填充的位置 [ l 1 , p o s ] [l_1, pos] [l1,pos],即将 [ l 1 , p o s ] [l_1, pos] [l1,pos] 区间置为 1, ( p o s ≤ r 1 ) (pos \le r_1) (pos≤r1)。因为 0 的个数具有单调性,所以可以通过二分来确定这个位置 p o s pos pos
时间复杂度为 O ( n l o g n + q l o g 2 n ) O(nlogn + qlog^2n) O(nlogn+qlog2n)
一些细节见代码
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 2e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
int n, m;
inline int ls(int x){return x << 1;}
inline int rs(int x){return x << 1 | 1;}
struct node{
int lmax, rmax; //脑洞,即0
int sum; //0的个数
int len;
int res; //最大连续0
int tag;
void set(int x){
lmax = rmax = sum = res = x;
}
node(){
lmax = rmax = sum = res = tag = len = 0;
}
}t[maxn << 2];
void pushup(node &k, node l, node r){
k.sum = l.sum + r.sum;
k.lmax = l.lmax;
if(l.len == l.sum)
k.lmax = l.len + r.lmax;
k.rmax = r.rmax;
if(r.len == r.sum)
k.rmax = r.len + l.rmax;
k.res = max(l.res, r.res);
k.res = max(k.res, l.rmax + r.lmax);
}
void build(int k, int l, int r){
t[k].len = r-l+1;
t[k].tag = 0;
if(l == r){
t[k].set(0);
return;
}
int mid = (l+r) >> 1;
build(ls(k), l, mid);
build(rs(k), mid+1, r);
pushup(t[k], t[ls(k)], t[rs(k)]);
return;
}
// tag = 0 : 无事发生
// tag = 1 : 全为脑洞 0
// tag = 2 : 全不脑洞 1
void pushdown(int k){
if(t[k].tag == 0)
return;
if(t[k].tag == 1){
t[ls(k)].set(t[ls(k)].len);
t[rs(k)].set(t[rs(k)].len);
}
else if(t[k].tag == 2){
t[ls(k)].set(0);
t[rs(k)].set(0);
}
t[ls(k)].tag = t[rs(k)].tag = t[k].tag;
t[k].tag = 0;
}
// v = 1 : 覆盖为脑洞
// v = 2 : 覆盖为脑组织
void modify(int k, int l, int r, int x, int y, int v){
if(x <= l && y >= r){
t[k].tag = v;
if(v == 1)
t[k].set(t[k].len);
else
t[k].set(0);
return;
}
int mid = (l+r) >> 1;
pushdown(k);
if(x <= mid)
modify(ls(k), l, mid, x, y, v);
if(y > mid)
modify(rs(k), mid+1, r, x, y, v);
pushup(t[k], t[ls(k)], t[rs(k)]);
}
// 查询 1(脑组织) 的个数
int querysum(int k, int l, int r, int x, int y){
if(x <= l && y >= r)
return t[k].len - t[k].sum;
int mid = (l+r) >> 1;
pushdown(k);
int ans = 0;
if(x <= mid)
ans += querysum(ls(k), l, mid, x, y);
if(y > mid)
ans += querysum(rs(k), mid+1, r, x, y);
return ans;
}
void change(int l0, int r0, int l1, int r1){
int cnt1 = querysum(1, 1, n, l0, r0);
modify(1, 1, n, l0, r0, 1);
if(cnt1 == 0)
return;
int l = l1, r = r1, pos = l1;
while(l <= r){
int mid = (l+r) >> 1;
int cnt0 = (mid-l1+1) - querysum(1, 1, n, l1, mid);
if(cnt0 <= cnt1){
pos = mid;
l = mid + 1;
}
else
r = mid - 1;
}
modify(1, 1, n, l1, pos, 2);
}
node query(int k, int l, int r, int x, int y){
if(x <= l && y >= r){
node x = t[k];
return x;
}
pushdown(k);
int mid = (l+r) >> 1;
node lson, rson, ans;
ans.len = r-l+1;
if(x <= mid)
lson = query(ls(k), l, mid, x, y);
if(y > mid)
rson = query(rs(k), mid+1, r, x, y);
pushup(ans, lson, rson);
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m;
build(1, 1, n);
while(m--){
int op, l0, r0, l1, r1;
cin >> op >> l0 >> r0;
if(op == 0)
modify(1, 1, n, l0, r0, 1);
else if(op == 1){
cin >> l1 >> r1;
change(l0, r0, l1, r1);
}
else if(op == 2){
node qres = query(1, 1, n, l0, r0);
cout << qres.res << endl;
}
}
return 0;
}