传送门:https://nanti.jisuanke.com/t/41399
题目描述
There are N N N light bulbs indexed from 0 0 0 to N − 1 N−1 N−1. Initially, all of them are off.
A F L I P FLIP FLIP operation switches the state of a contiguous subset of bulbs. F L I P ( L , R ) FLIP(L, R) FLIP(L,R) means to flip all bulbs xx such that L ≤ x ≤ R L \leq x \leq R L≤x≤R. So for example, F L I P ( 3 , 5 ) FLIP(3, 5) FLIP(3,5) means to flip bulbs 3 , 4 and 5, and F L I P ( 5 , 5 ) FLIP(5,5) FLIP(5,5) means to flip bulb 5.
Given the value of N N N and a sequence of M M M flips, count the number of light bulbs that will be on at the end state.
输入格式
The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a line containing two integers N and M, the number of light bulbs and the number of operations, respectively. Then, there are M more lines, the ii-th of which contains the two integers
L
i
L_i
Liand
R
i
R_i
Ri, indicating that the ii-th operation would like to flip all the bulbs from
L
i
L_i
Li
to
R
i
R_i
Ri, inclusive.
1 ≤ T ≤ 1000 1 \leq T \leq 1000 1≤T≤1000
1 ≤ N ≤ 1 0 6 1 \leq N \leq 10^6 1≤N≤106
1 ≤ M ≤ 1000 1 \leq M \leq 1000 1≤M≤1000
0 ≤ L i ≤ R i ≤ N − 1 0 \leq L_i \leq R_i \leq N-1 0≤Li≤Ri≤N−1
输出格式
For each test case, output one line containing Case # x : y x: y x:y, where x is the test case number (starting from 1) and y is the number of light bulbs that will be on at the end state, as described above.
样例输入
2
10 2
2 6
4 8
6 3
1 1
2 3
3 4
样例输出
Case #1: 4
Case #2: 3
① 线段树做法(MLE)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int t, n, m, x, y;
struct node { int l, r, sum, flip; } tree[maxn << 2];
inline const int read()
{
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
return x * f;
}
inline int ls(int id) { return id << 1; }
inline int rs(int id) { return id << 1 | 1; }
void push_up(int id)
{
tree[id].sum = tree[ls(id)].sum + tree[rs(id)].sum;
}
void push_down(int id)
{
if (tree[id].flip)
{
tree[ls(id)].flip ^= 1; tree[rs(id)].flip ^= 1;
tree[ls(id)].sum = tree[ls(id)].r - tree[ls(id)].l + 1 - tree[ls(id)].sum;
tree[rs(id)].sum = tree[rs(id)].r - tree[rs(id)].l + 1 - tree[rs(id)].sum;
tree[id].flip = 0;
}
}
void build(int id, int l, int r)
{
tree[id].l = l; tree[id].r = r;
tree[id].sum = tree[id].flip = 0;
if (l == r) return;
int mid = (l + r) >> 1;
build(ls(id), l, mid);
build(rs(id), mid + 1, r);
push_up(id);
}
void update(int id, int l, int r)
{
if (tree[id].l == l && tree[id].r == r)
{
tree[id].flip ^= 1;
tree[id].sum = r - l + 1 - tree[id].sum;
return;
}
push_down(id);
int mid = (tree[id].l + tree[id].r) >> 1;
if (r <= mid) update(ls(id), l, r);
else if (l > mid) update(rs(id), l, r);
else
{
update(ls(id), l, mid);
update(rs(id), mid + 1, r);
}
push_up(id);
}
int query(int id, int l, int r)
{
if (tree[id].l == l && tree[id].r == r) return tree[id].sum;
push_down(id);
int mid = (tree[id].l + tree[id].r) >> 1;
if (r <= mid) return query(ls(id), l, r);
if (l > mid) return query(rs(id), l, r);
return query(ls(id), l, mid) + query(rs(id), mid + 1, r);
}
int main()
{
t = read();
for (int i = 1; i <= t; i++)
{
printf("Case #%d: ", i);
n = read(); m = read();
build(1, 1, n);
while (m--)
{
x = read() + 1; y = read() + 1;
update(1, x, y);
}
printf("%d\n", query(1, 1, n));
}
return 0;
}
②
对于每一对Li、Ri,我们将其定义为:将Li之前的所有灯全都filp一次,再将Ri之前的所有灯全都filp一次,如图,即为将C段先翻转一次,再将A段翻转一次,这样一来,C段的灯被翻转了2次,即没有变化,而B段则被翻转了1次,达成了翻转[Li, Ri]区间的效果。
故,我们将所有的 Li(1 ~ Li-1)和 Ri+1(要包括Ri,故为Ri+1之前)保存在一个数组
v
v
v中,再将其由小到大排序遍历,维护在此坐标之前亮着的灯的数量
a
n
s
ans
ans(翻转一次即为
a
n
s
=
v
[
i
]
−
a
n
s
ans = v[i] - ans
ans=v[i]−ans)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int v[maxn];
inline const int read()
{
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
return x * f;
}
int main()
{
int t = read();
for (int i = 1; i <= t; i++)
{
int n = read(), m = read(), cnt = 0, ans = 0;
while (m--)
{
v[cnt++] = read();
v[cnt++] = read() + 1;
}
sort(v, v + cnt);
for (int j = 0; j < cnt; j++) ans = v[j] - ans;
printf("Case #%d: %d\n", i, ans);
}
return 0;
}