2021牛客多校3
题号 标题 团队的状态
A Guess and lies 通过
B Black and white 通过
C Minimum grid 通过
D Count 通过
E Math 通过
F 24dian 通过
G Yu Ling(Ling YueZheng) and Colorful Tree 通过
H Ling Qiu, Luna and Triple Backpack 未通过
I Kuriyama Mirai and Exclusive Or 通过
J Counting Triangles 通过

Guess and lies

Black and white

Minimum grid

Count

Math

24dian

Yu Ling(Ling YueZheng) and Colorful Tree

一棵 \(n\) 个点的树,1 是根。\(q\) 次操作:

  • 0 u x\(\mathrm{color}_u=x\)
  • 1 u l r x 询问离 \(u\) 的最近祖先 \(v\) 满足 \(l \leq \mathrm{color}_v \leq r, x \mid \mathrm{color}_v\)

\(n, q \leq 1.1\times 10^5, 1 \leq x \leq n\)染色操作的点和颜色都互不相同

跑一遍 dfs 序,祖先的限制转化为 \(\mathrm{in}_v \leq \mathrm{in}_u \leq \mathrm{out}_v\)

离线,将染色 \(x\) 和询问颜色 \(x\) 的操作都存下来,分别处理。

对于颜色 \(x\) 的询问,将 \(l, r\) 离散化,然后枚举 \(x\) 的倍数去掉 \(x \mid \mathrm{color}_v\) 的限制。

剩下来是一个三维偏序问题: \[ \begin{cases} t_v < t_u, \\ \mathrm{in}_v \leq \mathrm{in}_u \leq \mathrm{out}_v,\\ l \leq \mathrm{color}_v \leq r \end{cases} \] 可以树套树解决。

对于离散化后的颜色区间建立线段树,将询问和修改都挂在线段树上,去掉第三维。

然后对线段树的每个节点做一个二维偏序即可。

复杂度 \(O(n \log^3 n)\)

// Author:  HolyK
// Created: Sun Jul 25 14:59:29 2021
#include <bits/stdc++.h>
#define dbg(a...) fprintf(stderr, a)
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>;
inline char gc() {
  static constexpr int BufferSize = 1 << 22 | 5;
  static char buf[BufferSize], *p, *q;
  static std::streambuf *i = std::cin.rdbuf();
  return p == q ? p = buf, q = p + i->sgetn(p, BufferSize), p == q ? EOF : *p++ : *p++;
}
struct Reader {
  template <class T>
  Reader &operator>>(T &w) {
    char c, p = 0;
    for (; !std::isdigit(c = gc());) if (c == '-') p = 1;
    for (w = c & 15; std::isdigit(c = gc()); w = w * 10 + (c & 15)) ;
    if (p) w = -w;
    return *this;
  }
} cin;

constexpr int N(1.1e5 + 5);
int n, m;
std::vector<PII> g[N];
LL d[N];
int in[N], out[N], cnt;
void dfs(int x, int p) {
  in[x] = cnt++;
  for (auto [y, z] : g[x]) {
    if (y == p) continue;
    d[y] = d[x] + z;
    dfs(y, x);
  }
  out[x] = cnt;
}
int main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  cin >> n >> m;
  for (int i = 1, x, y, z; i < n; i++) {
    cin >> x >> y >> z;
    x--, y--;
    g[x].emplace_back(y, z);
    g[y].emplace_back(x, z);
  }
  d[0] = 1;
  dfs(0, -1);
  std::vector<PII> a(n + 1, PII(-1, -1));
  using Qry = std::array<int, 4>;
  std::vector<std::vector<Qry>> q(n + 1);
  std::vector<LL> ans(m);
  for (int i = 0; i < m; i++) {
    int opt, u, l, r, x;
    cin >> opt >> u;
    u--;
    if (opt == 0) {
      cin >> x;
      assert(a[x].first == -1);
      a[x] = {u, i};
      ans[i] = -1;
    } else {
      cin >> l >> r >> x;
      l = (l + x - 1) / x * x;
      r = (r + x) / x * x;
      ans[i] = 1e18;
      if (l < r) {
        q[x].push_back({u, l, r, i});
      }
    }
  }
  std::vector<int> p;
  std::vector<Qry> b;
  for (int x = 1; x <= n; x++) {
    if (q[x].empty()) continue;
    p.clear();
    for (auto [u, l, r, id] : q[x]) {
      p.push_back(l);
      p.push_back(r);
    }
    std::sort(p.begin(), p.end());
    p.resize(std::unique(p.begin(), p.end()) - p.begin());
    b.clear();
#define low(x) int(std::lower_bound(p.begin(), p.end(), x) - p.begin())
#define upp(x) int(std::upper_bound(p.begin(), p.end(), x) - p.begin())
    for (int y = p[0]; y < p.back(); y += x) {
      if (a[y].first == -1) continue;
      auto [u, id] = a[y];
      b.push_back({id, u, upp(y) - 1, -1});
    }
    for (auto [u, l, r, id] : q[x]) {
      b.push_back({id, u, low(l), low(r)});
    }
    std::sort(b.begin(), b.end());
    int s = 1 << std::__lg(p.size() * 2 - 1);
    std::vector<int> len(2 * s);
    for (auto [id, u, l, r] : b) {
      if (r == -1) {
        for (l += s; l; l >>= 1) {
          len[l]++;
        }
      } else {
        for (l += s, r += s; l < r; l >>= 1, r >>= 1) {
          if (l & 1) {
            len[l++]++;
          }
          if (r & 1) {
            len[--r]++;
          }
        }
      }
    }
    std::vector<std::vector<PII>> t(2 * s);
    for (int i = 1; i < 2 * s; i++) t.reserve(len[i]);
    
    for (auto [id, u, l, r] : b) {
      if (r == -1) {
        for (l += s; l; l >>= 1) {
          t[l].emplace_back(id, u);
        }
      } else {
        for (l += s, r += s; l < r; l >>= 1, r >>= 1) {
          if (l & 1) {
            t[l++].emplace_back(id, u);
          }
          if (r & 1) {
            t[--r].emplace_back(id, u);
          }
        }
      }
    }
    for (auto &v : t) {
      if (v.empty()) continue;
      p.clear();
      for (auto [id, u] : v) {
        if (~ans[id]) p.push_back(in[u]);
      }
      std::sort(p.begin(), p.end());
      p.resize(std::unique(p.begin(), p.end()) - p.begin());
      int s = 1 << std::__lg(p.size() * 2 - 1);
      std::vector<LL> max(2 * s);
      for (auto [id, u] : v) {
        if (ans[id] == -1) {
          for (int l = s + low(in[u]), r = s + low(out[u]); l < r; l >>= 1, r >>= 1) {
            if (l & 1) smax(max[l++], d[u]);
            if (r & 1) smax(max[--r], d[u]);
          }
        } else {
          LL m = 0;
          for (int l = s + low(in[u]); l; l >>= 1) {
            smax(m, max[l]);
          }
          if (m) smin(ans[id], d[u] - m);
        }
      }
    }
  }
  for (int i = 0; i < m; i++) {
    if (~ans[i]) {
      if (ans[i] < 1e18) {
        std::cout << ans[i] << "\n";
      } else {
        std::cout << "Impossible!\n";
      }
    }
  }
  return 0;
}

Ling Qiu, Luna and Triple Backpack

Kuriyama Mirai and Exclusive Or

Counting Triangles


最后修改于 2021-08-13