zoukankan      html  css  js  c++  java
  • Gym102059A Coloring Roads

    Gym102059A Coloring Roads


    题意:(n)点的树,一开始每条边都没有颜色,有(Q)个操作,每次将从(u)(1)路径上的所有边全部染色为颜色(c),之后询问整棵树上,出现了(m)次的颜色有多少种。数据范围均是(200000)

    做法:询问的东西十分奇怪没有办法下手,于是注意到每次的修改都是染色,而且染色的路径也很特殊。于是我们猜测在这种操作方式下,一条路径上连续相同的颜色段数有一个比较优秀的期望值。先考虑如何在一个序列上,进行赋值操作,我们想到了(ODT),在修改的同时维护每种颜色出现的次数和每种次数对应的颜色的种类数。对于每次询问的路径,通过树剖把问题转化到为序列上处理。。。

    #include <bits/stdc++.h>
    #define rep(i,a,b) for(int i = a; i <= b; ++i)
    #define pb push_back
    typedef long long ll;
    const int N = 1 << 18 | 5;
    template<class T> inline void read(T &x) {
        x = 0; char c = getchar(); T f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {x = x * 10 + c - '0'; c = getchar();}
        x *= f;
    }
    using namespace std;
    int n, C, Q;
    vector<int> G[N];
    int id[N], dfn, top[N], fa[N], sz[N], son[N];
    void dfs1(int u, int pre) {
        sz[u] = 1; fa[u] = pre;
        int weight = 0;
        for(int v: G[u]) if(v != pre) {
            dfs1(v, u);
            sz[u] += sz[v];
            if(weight < sz[v]) weight = sz[v], son[u] = v;
        }
    }
    void dfs2(int u, int tp) {
        top[u] = tp; id[u] = ++dfn;
        if(son[u]) dfs2(son[u],tp);
        for(int v: G[u]) if(v != fa[u] && v != son[u]) {
            dfs2(v,v);
        }
    }
    int ans[N], col[N];
    struct Seg{
        int l, r, c;
        bool operator < (const Seg &a) const {
            return r < a.r;
        }
    };
    set< Seg > S;
    void split(int p) {
        auto s = S.lower_bound({p,p});
        if(s == S.end() || (s->l) > p || p == s->r) return;
        int L = s->l, R = s->r, C = s->c;
        S.erase(s); S.insert({L,p,C}); S.insert({p+1,R,C});
    }
    void update(int L, int R, int C) {
        split(L-1); split(R);
        while(1) {
            auto s = S.lower_bound({L,L});
            if(s == S.end() || (s->l) > R) break;
            if(s->c) {
                -- ans[col[s->c]];
                col[s->c] -= s->r - s->l + 1;
                ++ ans[col[s->c]];
            }
            S.erase(s);
        }
        -- ans[col[C]];
        col[C] += R-L+1;
        ++ ans[col[C]];
        S.insert({L,R,C});
    }
    void solve(int u, int c) {
        while(u > 1) {
            int L = max(id[top[u]],2), R = id[u];
            if(L <= R) update(L,R,c);
            u = fa[top[u]];
        }
    }
    int main() {
        read(n), read(C), read(Q);
        rep(i,2,n) { int u, v;
            read(u), read(v);
            G[u].pb(v), G[v].pb(u);
        }
        dfs1(1,0); dfs2(1,1);
        ans[0] = C;
        S.insert({2,n,0});
        while(Q--) { int u, c, m;
            read(u), read(c), read(m);
            solve(u,c);
            printf("%d
    ",ans[m]);
        }
    }
    
  • 相关阅读:
    PTA L1-002 打印沙漏 (20分)
    音乐研究
    LeetCode 155. 最小栈
    LeetCode 13. 罗马数字转整数
    LeetCode 69. x 的平方根
    LeetCode 572. 另一个树的子树
    errno错误号含义
    僵尸进程和孤儿进程
    TCP和UDP相关概念
    图相关算法
  • 原文地址:https://www.cnblogs.com/RRRR-wys/p/10487085.html
Copyright © 2011-2022 走看看