1. 程式人生 > >Luogu3201 [HNOI2009]夢幻布丁

Luogu3201 [HNOI2009]夢幻布丁

code desc ret fprintf getchar() its clu n) bits

題目藍鏈

Description

\(n\)個點排成一列,每一個點都有一個顏色\(c_i\)。你需要支持下面兩個操作:

  1. 將一種顏色全部變為另一種顏色
  2. 詢問當前一共有多少個顏色段

Solution

我們可以考慮對於每一種顏色開一棵線段樹維護一下顏色出現的位置,線段樹的每一個節點記錄當前區間的顏色段數以及兩個端點是否有顏色。然後就直接合並,如果左區間的右端點和右區間的左端點都有顏色那麽就將顏色段數減一

然後對於\(1?\)操作我們就直接線段樹合並,然後\(2?\)操作就直接查詢一下對應顏色的根結點就可以了

Code

#include <bits/stdc++.h>

using namespace std;

#define fst first
#define snd second
#define mp make_pair
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }

inline int read() {
    int sum = 0, fg = 1; char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == ‘-‘) fg = -1;
    for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    return fg * sum;
}

const int maxn = 1e5 + 10;
const int maxm = 1e6 + 10;
const int inf = 1e6;

int n, m, rt[maxm];
namespace ST {
    int cnt;
    struct node {
        int ls, rs, v;
        bool L, R;
    }A[maxn << 6];
#define ls(x) A[x].ls
#define rs(x) A[x].rs
    inline void push_up(int rt) {
        A[rt].L = A[ls(rt)].L, A[rt].R = A[rs(rt)].R;
        A[rt].v = A[ls(rt)].v + A[rs(rt)].v;
        if (A[ls(rt)].R && A[rs(rt)].L) --A[rt].v;
    }
    inline void merge(int &x, int y, int l, int r) {
        if (!y) return;
        if (!x) { x = y; return; }
        int mid = (l + r) >> 1;
        merge(ls(x), ls(y), l, mid);
        merge(rs(x), rs(y), mid + 1, r);
        push_up(x);
    }
    inline void change(int &rt, int l, int r, int x) {
        if (!rt) rt = ++cnt;
        if (l == r) { ++A[rt].v, A[rt].L = A[rt].R = 1; return; }
        int mid = (l + r) >> 1;
        if (x <= mid) change(ls(rt), l, mid, x);
        else change(rs(rt), mid + 1, r, x);
        push_up(rt);
    }
    inline int query(int rt) { return A[rt].v; }
}

int main() {
#ifdef xunzhen
    freopen("dream.in", "r", stdin);
    freopen("dream.out", "w", stdout);
#endif

    n = read(), m = read();
    for (int i = 1; i <= n; i++) ST::change(rt[read()], 1, n, i);
    int ans = 0;
    for (int i = 1; i <= inf; i++) ans += ST::query(rt[i]);
    for (int i = 1; i <= m; i++) {
        int op = read();
        if (op == 2) printf("%d\n", ans);
        else {
            int x = read(), y = read();
            if (x == y) continue;
            ans -= ST::query(rt[x]) + ST::query(rt[y]);
            ST::merge(rt[y], rt[x], 1, n);
            ans += ST::query(rt[y]);
            rt[x] = 0;
        }
    }

    return 0;
}

Luogu3201 [HNOI2009]夢幻布丁