传送门:https://nanti.jisuanke.com/t/41399
题目描述
There are light bulbs indexed from to . Initially, all of them are off.
A operation switches the state of a contiguous subset of bulbs. means to flip all bulbs xx such that . So for example, means to flip bulbs 3 , 4 and 5, and means to flip bulb 5.
Given the value of and a sequence of 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
and
, indicating that the ii-th operation would like to flip all the bulbs from
to
, inclusive.
输出格式
For each test case, output one line containing Case # , 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之前)保存在一个数组
中,再将其由小到大排序遍历,维护在此坐标之前亮着的灯的数量
(翻转一次即为
)
#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;
}