• Codeforces620E New Year Tree


    挺好的一道题

    Description

    link

    给一棵树,每个点有颜色 (c_i) 为点权,需要实现以下两种操作:

    子树修改颜色(覆盖),查询子树颜色种类

    (n leq 4 imes 10^5,c_i leq 60)

    Solution

    首先看到子树和修改啥的,直接思考 (dfs) 序加线段树(从树剖学来的)

    我们看到如果对于每一个点开桶进行统计,可能不太现实

    然后审题的关键点就来了:(c_i leq 60)

    可以开 ( m{long long}) 状压

    然后就成了单点进行答案统计

    最后把对应 (query) 搞个 (lowbit) 什么的整一下 (1) 就好了(从树状数组剽来的)

    要注意 (1ll<<)的问题

    Code

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm {
    inline int read() {
        int res = 0, f = 1;
        char k;
        while (!isdigit(k = getchar()))
            if (k == '-')
                f = -1;
        while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
        return res * f;
    }
    const int N = 4e5 + 10;
    int a[N], fa[N], dep[N], head[N], cnt, in[N], out[N], tim, opt, n, m, id[N];
    struct node {
        int nxt, to;
    } e[N << 2];
    inline void add1(int u, int v) {
        e[++cnt].nxt = head[u];
        e[cnt].to = v;
        return head[u] = cnt, void();
    }
    struct tree {
        int l, r, sum, add;
    #define l(p) t[p].l
    #define r(p) t[p].r
    #define sum(p) t[p].sum
    #define add(p) t[p].add
    } t[N << 2];
    inline void push_up(int p) {
        sum(p) = sum(p << 1) | sum(p << 1 | 1);
        return;
    }
    inline void build(int p, int l, int r) {
        l(p) = l;
        r(p) = r;
        if (l == r)
            return sum(p) = 1ll << a[id[l]], void();
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        return push_up(p);
    }
    inline int lowbit(int x) { return x & (-x); }
    inline void spread(int p) {
        if (add(p)) {
            sum(p << 1) = add(p);
            sum(p << 1 | 1) = add(p);
            add(p << 1) = add(p);
            add(p << 1 | 1) = add(p);
        }
        return add(p) = 0, void();
    }
    inline void update(int p, int l, int r, int c) {
        if (l <= l(p) && r(p) <= r)
            return add(p) = 1ll << c, sum(p) = 1ll << c, void();
        spread(p);
        int mid = (l(p) + r(p)) >> 1;
        if (l <= mid)
            update(p << 1, l, r, c);
        if (r > mid)
            update(p << 1 | 1, l, r, c);
        return push_up(p);
    }
    inline int query(int p, int l, int r) {
        if (l <= l(p) && r(p) <= r)
            return sum(p);
        spread(p);
        int ans = 0, mid = (l(p) + r(p)) >> 1;
        if (l <= mid)
            ans |= query(p << 1, l, r);
        if (r > mid)
            ans |= query(p << 1 | 1, l, r);
        return ans;
    }
    inline int ask1(int x) {
        int ret = 0;
        for (; x; x -= lowbit(x)) ret++;
        return ret;
    }
    inline void dfs(int x, int f) {
        in[x] = ++tim;
        id[tim] = x;
        fa[x] = f;
        for (int i = head[x]; i; i = e[i].nxt) {
            int t = e[i].to;
            if (t == f)
                continue;
            dfs(t, x);
        }
        return out[x] = tim, void();
    }
    signed main() {
        n = read(), m = read();
        for (int i = 1; i <= n; ++i) a[i] = read();
        for (int i = 1, u, v; i < n; ++i) u = read(), v = read(), add1(u, v), add1(v, u);
        dfs(1, 0);
        build(1, 1, n);
        while (m--) {
            opt = read();
            if (opt == 1) {
                int x = read(), c = read();
                update(1, in[x], out[x], c);
            } else {
                int x = read();
                int tmp = query(1, in[x], out[x]);
                printf("%lld
    ", ask1(tmp));
            }
        }
        return 0;
    }
    }  // namespace yspm
    signed main() { return yspm::main(); }
    
  • 相关阅读:
    写了一个自动打包并发布到tomcat的脚本
    查看并更改mysql编码
    MyBatis无法根据中文条件查询出结果
    服务器端PHP多进程编程
    PHP-popen()&nbsp;函数打开进程文件指针
    php并发处理
    PHP能得到你是从什么页面过来的,r…
    PHP如何解决网站大流量与高并发的…
    基于PHP的cURL快速入门
    Mysql内存表的用处
  • 原文地址:https://www.cnblogs.com/yspm/p/12369912.html
Copyright © 2020-2023  润新知