You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
3.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}