zoukankan      html  css  js  c++  java
  • [ABC219]G

    一开始我还想着用什么数据结构去维护的,想了好久没想出来。

    其实看范围就应该想到n根号n能过的。

    题意就是说每个点都有自己的颜色,给你q个操作,每次操作将这个点的颜色扩散给相邻点。问你q个操作之后每个点的颜色是什么。

    首先我们暴力做复杂度是O(q*m)的这样肯定是不行的,于是我们想到优化。难道我们真的需要每个点都去暴力跑相邻点吗?

    于是从这个点出发,如果一个点邻接点太多了,那么我们就用标记把这次操作O(1)化。假设我们设置这个太多的定义就是这个点的度超过了 lmt。

    参考博客:https://www.cnblogs.com/Kanoon/p/15312156.html

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    typedef pair<int, int> pii;
    const int inf = 0x3f3f3f3f; ///1061109567
    const int maxn = 2e5 + 10;
    
    vector<int> G1[maxn]; ///邻接点
    vector<int> G2[maxn]; ///度 >= lmt 的邻接点
    
    pii ans[maxn], tag[maxn]; ///最终答案数组,标记数组
    
    int main() {
        int n, m, q; cin >> n >> m >> q;
        int lmt = sqrt(2*m); ///设置lmt
    
        for (int i = 1; i <= m; ++ i) {
            int u, v; cin >> u >> v;
            G1[u].push_back(v);
            G1[v].push_back(u);
        }
        ///数组初始化
        for (int i = 1; i <= n; ++ i) {
            ans[i] = tag[i] = {i, -1};
        }
    
        ///预处理出所有点的邻接点中度大于lmt的点
        for (int u = 1; u <= n; ++ u) {
            for (auto v : G1[u]) {
                if (G1[v].size() >= lmt) {
                    G2[u].push_back(v);
                }
            }
        }
        for (int i = 1; i <= q; ++ i) {
            int u; cin >> u;
            ///用大于 lmt的邻接点去更新当前点
            ///因为大于lmt的点我们是打标记,实际上我们并没有更新
            ///所以当这个点拥有大于lmt的点时我们需要更新上来,跟之前暴力更新的值取大
    
            /// O(2*m / lmt)
            for (auto v : G2[u]) {
                if (ans[u].second < tag[v].second) {
                    ans[u] = tag[v];
                }
            }
    
            /// O(lmt)
            if (G1[u].size() < lmt) { ///当前点度小于lmt,暴力更新
                for (auto v : G1[u]) {
                    ans[v] = {ans[u].first, i};
                }
            }
            else { ///大于lmt,打上标记
                tag[u] = {ans[u].first, i};
            }
    
            ///所以复杂度为 O(q * (2*m / lmt + lmt))
        }
        ///由于小于lmt的点我们已经暴力更新了,剩下的只需要用大于lmt的点去更新当前答案即可
        for (int u = 1; u <= n; ++ u) {
            for (auto v : G2[u]) {
                if (ans[u].second < tag[v].second) {
                    ans[u] = tag[v];
                }
            }
            cout << ans[u].first << " 
    "[u == n];
        }
    
        return 0;
    }
  • 相关阅读:
    7-36 复数四则运算
    7-35 有理数均值
    7-34 通讯录的录入与显示
    7-33 有理数加法
    7-32 说反话-加强版
    POJ-2524-Ubiquitous Religions
    POJ-2406-Power Strings
    HDU-1072-Nightmares
    POJ-1961-Period(ZOJ-2177)
    POJ-1961-Period(ZOJ-2177)
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/15318274.html
Copyright © 2011-2022 走看看