zoukankan      html  css  js  c++  java
  • [APIO2019]桥梁

    • 给定边带权的无向图 ((V,E))(q) 次操作,改变一条边的权值或者询问从 (s_i) 出发只走权值大于等于 (w_i) 的边能够到达的点数。
    • (|V| leq 5 imes 10^4, |E|, q leq 10^5)

    分别考虑涉及修改和不涉及修改的边:

    • 对于不涉及修改的边,将询问从大到小排序,然后从大到小加边用并查集维护联通块。这部分是 (O(|E| log |E| + q log q))
    • 对于涉及修改的边,每次询问暴力访问询问之前的修改,满足条件就加入并查集。这部分是 (O(q^2log q))

    将操作分块,设块大小为 (S),第一部分变为 (O(|E|log |E| + S log S)),第二部分变为 (O(S^2log S))

    总复杂度 (O(frac qS|E|log|E| + qSlog S)),大概算一下块大小,卡常。

    #include <bits/stdc++.h>
    #define dbg(...) std::cerr << "33[32;1m", fprintf(stderr, __VA_ARGS__), std::cerr << "33[0m"
    template <class T, class U>
    inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
    template <class T, class U>
    inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }
    using LL = long long;
    using PII = std::pair<int, int>;
    
    constexpr int N(5e4 + 5), S(500);
    int fa[N], siz[N];
    int find(int x) {
      while (fa[x] != x) x = fa[x];
      return x;
    }
    int main() {
      std::ios::sync_with_stdio(false);
      std::cin.tie(nullptr);
      int n, m, q;
      std::cin >> n >> m;
      std::vector<std::array<int, 3>> e(m);
      for (auto &[x, y, z] : e) std::cin >> x >> y >> z;
      std::vector<int> eq(m);
      std::iota(eq.begin(), eq.end(), 0);
      auto cmp_edge = [&](int i, int j) { return e[i][2] > e[j][2]; };
      std::sort(eq.begin(), eq.end(), cmp_edge);
      std::cin >> q;
      for (int i = 0; i < q; i += S) {
        std::vector<std::array<int, 3>> a, b;
        std::vector<char> vis(m);
        for (int j = 0; j < S && i + j < q; j++) {
          int t, x, y;
          std::cin >> t >> x >> y;
          if (t == 1) {
            vis[--x] = 1;
            a.push_back({ j, x, y });
          } else {
            b.push_back({ j, x, y });
          }
          (t == 1 ? a : b).push_back({ j, x, y });
        }
        std::sort(b.begin(), b.end(), [](const auto &x, const auto &y) { return x[2] > y[2]; });
        std::vector<int> c, d, ans(a.size() + b.size());
        for (int j = 0; j < m; j++) {
          if (!vis[eq[j]]) {
            c.push_back(eq[j]);
          } else {
            d.push_back(eq[j]);
          }
        }
        std::iota(fa, fa + n + 1, 0);
        std::fill(siz, siz + n + 1, 1);
        auto p = c.begin();
        for (auto &[t, s, w] : b) {
          for (; p != c.end() && e[*p][2] >= w; p++) {
            int x = find(e[*p][0]), y = find(e[*p][1]);
            if (x == y) continue;
            if (siz[x] > siz[y]) std::swap(x, y);
            fa[x] = y, siz[y] += siz[x];
          }
          
          std::vector<int> pre(d.size());
          for (int j = 0; j < d.size(); j++) {
            pre[j] = e[d[j]][2];
          }
          for (auto &[tt, x, y] : a) {
            if (tt > t) continue;
            e[x][2] = y;
          }
          std::vector<std::array<int, 3>> v;
          for (int j : d) {
            if (e[j][2] >= w) {
              int x = find(e[j][0]), y = find(e[j][1]);
              if (x == y) continue;
              if (siz[x] > siz[y]) std::swap(x, y);
              v.push_back({ x, y, fa[x] });
              fa[x] = y, siz[y] += siz[x];
            }
          }
          ans[t] = siz[find(s)];
          while (!v.empty()) {
            auto &[x, y, z] = v.back();
            fa[x] = z, siz[y] -= siz[x];
            v.pop_back();
          }
          for (int j = 0; j < d.size(); j++) {
            e[d[j]][2] = pre[j];
          }
        }
        for (int i : ans) if (i) std::cout << i << "
    ";
        for (auto &[t, x, y] : a) e[x][2] = y;
        std::sort(d.begin(), d.end(), cmp_edge);
        std::merge(c.begin(), c.end(), d.begin(), d.end(), eq.begin(), cmp_edge);
      }
      return 0;
    }
    
    
  • 相关阅读:
    java学习——abstract 和 final
    apache配置访问目录的默认页面
    Beyond Compare 4
    idea常用插件
    linux关闭防火墙
    本地项目上传到gitlab
    删除数据库中多余的数据
    git上传本地项目到gitlab
    谷歌浏览器插件
    域名
  • 原文地址:https://www.cnblogs.com/HolyK/p/14332957.html
Copyright © 2011-2022 走看看