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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章