小夏有一台神奇的计算机,这个计算机有n个开关,初始状态均为关,
接下来,小夏想对这台计算机进行m次操作,每次操作给出三个数l,r,k,
表示将第l个(含l)到第r个(含r)开关的状态设置为开或者关(k=0表示关、k=1表示开)
m次操作完之后,小夏想知道这台计算机中,
有多少个区间满足开启状态开关的个数等于关闭状态开关的个数
heltion代码
先离散化,配合set乱搞(可用时间逆序+set二分,或用珂朵莉树),将序列分成若干个0、1区间
01区间开关个数相等,
可以把1看成(,遇到(就+1,把0看成是),遇到)就-1,
从而转化为前缀值域相等的问题,
每一段区间[l,r),记录区间开始的前缀和值和区间终止时的前缀和值,
再按照值域差分,每一个区间对应区间加1,最后统计每段值域的出现次数
对于某一段值域[l,r),其中的每个值的出现次数都相等,
设出现次数为x,则C(x,2)就能找到两个合法端点L-1和R,确定题目所求区间[L,R]
partial_sum(sum.begin(), sum.end(), sum.begin()); // 对sum数组做前缀和,并保存到sum内
#include
using namespace std;
using LL = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector l(m), r(m), k(m);
set s;
s.insert(1);
s.insert(n + 1);
for (int i = 0; i < m; i += 1) {
cin >> l[i] >> r[i] >> k[i];
s.insert(l[i]);
s.insert(r[i] + 1);
}
set> sp;
for (auto it = s.begin(); next(it) != s.end(); it = next(it)) {
sp.emplace(*it, *next(it));
}
set> st;
for (int i = m - 1; i >= 0; i -= 1) {
for (auto it = sp.lower_bound(make_pair(l[i], 0));
it != sp.end() and it->first <= r[i]; it = sp.erase(it)) {
st.emplace(it->first, it->second, k[i]);
}
}
for (auto [l, r] : sp) {
st.emplace(l, r, 0);
}
vector> vp;
vp.emplace_back(0, 1);
int cur = 0;
for (auto [l, r, k] : st) {
if (k) {
vp.emplace_back(cur + 1, cur + r - l + 1);
cur += r - l;
} else {
vp.emplace_back(cur + l - r, cur);
cur += l - r;
}
}
vector x;
for (auto [l, r] : vp) {
x.emplace_back(l);
x.emplace_back(r);
}
sort(x.begin(), x.end());
x.erase(unique(x.begin(), x.end()), x.end());
vector sum(x.size());
for (auto [l, r] : vp) {
sum[lower_bound(x.begin(), x.end(), l) - x.begin()] += 1;
sum[lower_bound(x.begin(), x.end(), r) - x.begin()] -= 1;
}
partial_sum(sum.begin(), sum.end(), sum.begin());
LL ans = 0;
for (int i = 0; i + 1 < x.size(); i += 1) {
ans += (LL)sum[i] * (sum[i] - 1) / 2 * (x[i + 1] - x[i]);
}
cout << ans;
}
后面的逻辑相同,前面的区间覆盖用珂朵莉树维护
1. split将包含x的区间[l,r)拆成两个区间[l,x)和[x,r)
2. assign将[l,r]内的每个区间删掉,合并为同一个[l,r],赋值为k
#include "bits/stdc++.h"
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
map mp;
mp[1] = 0;
mp[n + 1] = 0;
auto split = [&](int x) {
auto it = prev(mp.upper_bound(x));
mp[x] = it->second;
};
auto assign = [&](int l, int r, int k) {
split(l);
split(r + 1);
auto it = mp.find(l);
while (it->first != r + 1) {
it = mp.erase(it);
}
mp[l] = k;
};
for (int i = 0; i < m; i++) {
int l, r, k;
cin >> l >> r >> k;
assign(l, r, k);
}
vector> a;
a.push_back({0, 1});
int cur = 0;
for (auto it = mp.begin(); it != prev(mp.end()); it++) {
auto &[u, v] = *it;
int l = u;
int r = next(it)->first;
int k = v;
if (k) {
a.push_back({cur + 1, cur + (r - l) + 1});
cur += (r - l);
} else {
a.push_back({cur - (r - l), cur});
cur -= (r - l);
}
}
vector b;
for (auto &[l, r] : a) {
b.push_back(l);
b.push_back(r);
}
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());
int N = b.size();
vector pre(N);
for (auto &[l, r] : a) {
pre[lower_bound(b.begin(), b.end(), l) - b.begin()]++;
pre[lower_bound(b.begin(), b.end(), r) - b.begin()]--;
}
for (int i = 0; i + 1 < N; i++) {
pre[i + 1] += pre[i];
}
i64 ans = 0;
for (int i = 0; i + 1 < N; i++) {
ans += pre[i] * (pre[i] - 1) / 2 * (b[i + 1] - b[i]);
}
cout << ans << '\n';
return 0;
}