読者です 読者をやめる 読者になる 読者になる

mayoko’s diary

プロコンとかいろいろ。

Educational Codeforces Round 6 E. New Year Tree

解法

見た目が明らかに Euler Tour + 遅延評価セグ木 です。今回, 色の種類が 60 種類しかないので, セグメント木には, 2^c[i] (色 c[i] が含まれるかどうかのフラグ) というのの OR を取る形のものを保持しておけば良いです。

struct ST {
    vector<ll> seg, lazy;
    int size;

    ST(int n) {
        size = 1;
        while (size < n) size *= 2;
        seg.resize(size * 2);
        lazy.resize(size * 2, -1);
    }

    inline void push(int k, int l, int r) {
        if (lazy[k] != -1) {
            seg[k] = lazy[k];
            if (r - l > 1) {
                lazy[k * 2 + 1] = lazy[k];
                lazy[k * 2 + 2] = lazy[k];
            }
            lazy[k] = -1;
        }
    }

    inline ll merge(ll x, ll y) {
        return x | y;
    }

    void update(int a, int b, ll v, int k, int l, int r) {
        push(k, l, r);
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            lazy[k] = v;
            push(k, l, r);
        } else {
            update(a, b, v, k * 2 + 1, l, (l + r) / 2);
            update(a, b, v, k * 2 + 2, (l + r) / 2, r);
            seg[k] = merge(seg[k * 2 + 1], seg[k * 2 + 2]);
        }
    }

    void update(int a, int b, ll v) {
        return update(a, b, v, 0, 0, size);
    }

    ll query(int a, int b, int k, int l, int r) {
        push(k, l, r);
        if (r <= a || b <= l) return 0;
        if (a <= l && r <= b) return seg[k];
        ll x = query(a, b, k * 2 + 1, l, (l + r) / 2);
        ll y = query(a, b, k * 2 + 2, (l + r) / 2, r);
        return merge(x, y);
    }

    ll query(int a, int b) {
        return query(a, b, 0, 0, size);
    }
};

// Euler-Tour
const int MAXSIZE = 400020;
int BEGIN[MAXSIZE], END[MAXSIZE];
vector<int> euler_tour;
int K;
vector<vi> G;

void createEulerTour(int v, int p) {
    BEGIN[v] = K++;
    euler_tour.push_back(v);
    for (int el : G[v]) {
        if (el == p) continue;
        createEulerTour(el, v);
        euler_tour.push_back(v);
        K++;
    }
    END[v] = K;
}

int C[400400];

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    G.resize(n);
    for (int i = 0; i < n; i++) {
        scanf("%d", C+i);
        C[i]--;
    }
    for (int i = 0; i < n-1; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        x--; y--;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    createEulerTour(0, -1);
    ST segs(euler_tour.size());
    for (int i = 0; i < n; i++) {
        segs.update(BEGIN[i], BEGIN[i]+1, 1ll<<C[i]);
    }
    while (m--) {
        int t;
        scanf("%d", &t);
        if (t==1) {
            int v, c;
            scanf("%d %d", &v, &c);
            v--; c--;
            segs.update(BEGIN[v], END[v], 1ll<<c);
        } else {
            int v;
            scanf("%d", &v);
            v--;
            int ans = __builtin_popcountll(segs.query(BEGIN[v], END[v]));
            printf("%d\n", ans);
        }
    }
    return 0;
}