The Preliminary Contest for ICPC Asia Shanghai 2019 B. Light bulbs(卡了线段树空间的思维题)

传送门:https://nanti.jisuanke.com/t/41399

题目描述

There are NN light bulbs indexed from 00 to N1N−1. Initially, all of them are off.

A FLIPFLIP operation switches the state of a contiguous subset of bulbs. FLIP(L,R)FLIP(L, R) means to flip all bulbs xx such that LxRL \leq x \leq R. So for example, FLIP(3,5)FLIP(3, 5) means to flip bulbs 3 , 4 and 5, and FLIP(5,5)FLIP(5,5) means to flip bulb 5.

Given the value of NN and a sequence of MM 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 LiL_iand RiR_i, indicating that the ii-th operation would like to flip all the bulbs from LiL_i
to RiR_i, inclusive.

1T10001 \leq T \leq 1000

1N1061 \leq N \leq 10^6

1M10001 \leq M \leq 1000

0LiRiN10 \leq L_i \leq R_i \leq N-1

输出格式

For each test case, output one line containing Case #x:yx: 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之前)保存在一个数组vv中,再将其由小到大排序遍历,维护在此座标之前亮着的灯的数量ansans(翻转一次即为 ans=v[i]ansans = 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章