|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
|
|
|
#define int long long
|
|
|
#define N 1000100
|
|
|
|
|
|
// 柯朵莉树
|
|
|
// O2优化后,也过不去最后的两个测试点TLE
|
|
|
int n, m;
|
|
|
struct Node {
|
|
|
int l, r;
|
|
|
mutable int v;
|
|
|
Node(int L, int R = 0, int V = 0) :
|
|
|
l(L), r(R), v(V) {
|
|
|
}
|
|
|
bool operator<(const Node &t) const {
|
|
|
return l < t.l;
|
|
|
}
|
|
|
};
|
|
|
set<Node> s;
|
|
|
|
|
|
set<Node>::iterator split(int p) {
|
|
|
auto it = s.lower_bound(Node(p));
|
|
|
if (it != s.end() && it->l == p) return it;
|
|
|
it--;
|
|
|
int l = it->l, r = it->r, v = it->v;
|
|
|
s.erase(it);
|
|
|
s.insert(Node(l, p - 1, v));
|
|
|
return s.insert(Node(p, r, v)).first;
|
|
|
}
|
|
|
|
|
|
void assign(int l, int r, int v) {
|
|
|
auto R = split(r + 1), L = split(l);
|
|
|
s.erase(L, R);
|
|
|
s.insert(Node(l, r, v));
|
|
|
}
|
|
|
|
|
|
// 本题逻辑,区间修改[l1,r1]--->[l2,r2]
|
|
|
void change(int l1, int r1, int l2, int r2) {
|
|
|
int res = 0;
|
|
|
auto R = split(r1 + 1), L = split(l1), it = L;
|
|
|
for (; L != R; L++)
|
|
|
if (L->v == 1) res += (L->r - L->l + 1); // 记录正常脑组织的个数
|
|
|
|
|
|
s.erase(it, R); // 删除旧区间
|
|
|
s.insert(Node(l1, r1, 0)); // 旧区间清零
|
|
|
|
|
|
if (!res) return; // 如果这里面没有正常脑组织,那还修什么修
|
|
|
|
|
|
R = split(r2 + 1), L = split(l2), it = L;
|
|
|
|
|
|
// 个人理解属于优化,事实也是如此,但优化后效果是一样的,还是挂了两个测试点TLE
|
|
|
// if (res >= r2 - l2 + 1) { // 如果正常脑组织的个数,超过预修补区间的长度,那么多余的扔掉
|
|
|
// s.erase(L, R);
|
|
|
// s.insert(Node(l2, r2, 1));
|
|
|
// return;
|
|
|
// }
|
|
|
|
|
|
// 小于等于目标区间长度
|
|
|
for (; L != R; L++) {
|
|
|
if (L->v == 0) {
|
|
|
res -= L->r - L->l + 1; // 利用正常的脑组织进行修补
|
|
|
if (res < 0) { // 如果正常脑组织放在这个区间不够
|
|
|
assign(L->l, L->r + res, 1); // 能修多少算多少
|
|
|
break; // 剩余的使没了,不用再往下查看了
|
|
|
} else
|
|
|
L->v = 1; // 暴力修改此区域的值v=1
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int query(int l, int r) {
|
|
|
auto R = split(r + 1), L = split(l);
|
|
|
int res = 0, sum = 0;
|
|
|
for (; L != R; L++) {
|
|
|
if (L->v == 0) // 如果区间值为0,累加计算本轮可以获取到的最长连续0长度,准备参加PK大赛
|
|
|
sum += L->r - L->l + 1;
|
|
|
else
|
|
|
// 如果区间不为0,则以上一轮的最长的、区间内都是0的长度是多少
|
|
|
// 不断进行PK大赛,选举出最长的区间最大的连续脑洞区域
|
|
|
res = max(res, sum), sum = 0;
|
|
|
}
|
|
|
// 这里有技巧!一般我们直接返回res,但是这里不行,因为如果最后一块是连续的0,那么else的代码将无法执行,造成结果错误,需要最后补一下检查
|
|
|
return max(res, sum);
|
|
|
}
|
|
|
|
|
|
signed main() {
|
|
|
// 加快读入
|
|
|
ios::sync_with_stdio(false), cin.tie(0);
|
|
|
cin >> n >> m;
|
|
|
|
|
|
// 柯朵莉初始化
|
|
|
// 最初是没有脑洞的,全部是正常的大脑,都是1
|
|
|
s.insert(Node(1, n, 1));
|
|
|
|
|
|
while (m--) {
|
|
|
int op, l, r;
|
|
|
cin >> op >> l >> r;
|
|
|
if (op == 0) assign(l, r, 0); //[l,r]之间挖出脑洞
|
|
|
if (op == 1) { // 进行了一次脑洞治疗,从[l1,r1]--->[l2,r2]进行修补
|
|
|
int l2, r2;
|
|
|
cin >> l2 >> r2;
|
|
|
change(l, r, l2, r2);
|
|
|
}
|
|
|
// 询问 [l, r] 区间内最大的脑洞有多大.也就是有多少个0
|
|
|
if (op == 2) cout << query(l, r) << endl;
|
|
|
}
|
|
|
return 0;
|
|
|
} |