QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#112283#6559. A Tree and Two EdgesITMO_pengzoo#RE 2ms3492kbC++206.4kb2023-06-11 01:53:012023-06-11 01:53:06

Judging History

你现在查看的是最新测评结果

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2023-06-11 01:53:06]
  • 评测
  • 测评结果:RE
  • 用时:2ms
  • 内存:3492kb
  • [2023-06-11 01:53:01]
  • 提交

answer

//  Nikita Golikov, 2023

#include <bits/stdc++.h>

using namespace std;

using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;

#ifdef GOLIKOV
  #include "/Users/golikovnik/contests/debug.h"
#else
  #define debug(...) ;
#endif

template <class A, class B>
bool smin(A& x, B&& y) {
  if (y < x) {
    x = y;
    return true;
  }
  return false;
}

template <class A, class B>
bool smax(A& x, B&& y) {
  if (x < y) {
    x = y;
    return true;
  }
  return false;
}

struct LCA {
  vector<vector<int>> graph;
  int root;
  int n;
  vector<int> parent, jump, depth, tin, tout;
  int timer;

  LCA(vector<vector<int>> g, int root_ = 0) : graph(move(g)), root(root_) {
    n = int(graph.size());
    build();
  }

  template <class F>
  int up(int v, F const& f) {
    while (v != root) {
      int jv = jump[v];
      if (f(jv)) {
        v = jv;
      } else {
        int pv = parent[v];
        if (f(pv)) {
          v = pv;
        } else {
          return v;
        }
      }
    }
    return root;
  }

  int up(int v, int d) {
    int nd = depth[v] - d;
    assert(nd >= 0);
    return up(v, [&](int u) {
      return depth[u] >= nd;
    });
  }

  bool anc(int v, int u) {
    return tin[v] <= tin[u] && tout[u] <= tout[v];
  }

  int lca(int u, int v) {
    return anc(u, v) ? u : parent[up(u, [&](int x) { return !anc(x, v); })];
  }

  int operator()(int u, int v) {
    return lca(u, v);
  }

  int dist(int u, int v) {
    return depth[u] + depth[v] - 2 * depth[lca(u, v)];
  }

  //  kth vertex on path u->v
  int kth(int u, int v, int k) {
    int w = lca(u, v);
    assert(k <= depth[u] + depth[v] - 2 * depth[w]);
    if (k <= depth[u] - depth[w]) {
      return up(u, k);
    }
    k -= depth[u] - depth[w];
    return up(v, depth[v] - depth[w] - k);
  }

  void dfs(int v) {
    tin[v] = timer++;
    for (int u : graph[v]) {
      if (u == parent[v]) {
        continue;
      }
      depth[u] = depth[v] + 1;
      parent[u] = v;
      int dpar = depth[v];
      int dparj = depth[jump[v]];
      int dparjj = depth[jump[jump[v]]];
      jump[u] = (dparj - dpar == dparjj - dparj ? jump[jump[v]] : v);
      dfs(u);
    }
    tout[v] = timer;
  }

  void build() {
    parent.resize(n, -1);
    jump.resize(n, -1);
    depth.resize(n, -1);
    tin.resize(n, -1);
    tout.resize(n, -1);
    timer = 0;
    depth[root] = 0;
    parent[root] = jump[root] = root;
    dfs(root);
  }
};

int main() {
#ifdef GOLIKOV
  assert(freopen("in", "rt", stdin));
  auto _clock_start = chrono::high_resolution_clock::now();
#endif
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n, q;
  cin >> n >> q;
  vector<vector<int>> graph(n);
  for (int i = 0; i < n + 1; ++i) {
    int u, v;
    cin >> u >> v;
    --u, --v;
    graph[u].push_back(v);
    graph[v].push_back(u);
  }

  vector<bool> used(n);
  vector<pair<int, int>> back;
  vector<int> par(n);
  vector<int> dep(n);
  vector sum(4, vector<int>(n));
  auto dfs = [&](auto self, int v, int p = -1) -> void {
    used[v] = true;
    for (int u : graph[v]) {
      if (u == p) {
        continue;
      }
      if (used[u]) {
        if (dep[u] > dep[v]) {
          back.emplace_back(u, v);
        }
      } else {
        dep[u] = dep[v] + 1;
        par[u] = v;
        self(self, u, v);
      }
    }
  };

  dfs(dfs, 0);
  assert(int(back.size()) == 2);
  vector<int> fe(n);
  for (int i = 0; i < 2; ++i) {
    auto[u, v] = back[i];
    while (u != v) {
      fe[u] |= 1 << i;
      u = par[u];
    }
  }
  fill(used.begin(), used.end(), false);
  vector<vector<int>> tree(n);
  vector<int> total(4);
  auto dfs2 = [&](auto self, int v, int p = -1) -> void {
    used[v] = true;
    for (int u : graph[v]) {
      if (u == p) {
        continue;
      }
      total[fe[u]] += 1;
      if (!used[u]) {
        tree[v].push_back(u);
        tree[u].push_back(v);
        for (int t = 0; t < 4; ++t) {
          sum[t][u] += sum[t][v];
        }
        sum[fe[u]][u] += 1;
        self(self, u, v);
      }
    }
  };
  dfs2(dfs2, 0);
  auto lca = LCA(tree);
  auto GetCnt = [&](int t, int u, int v) {
    return sum[t][u] + sum[t][v] - 2 * sum[t][lca(u, v)];
  };
  vector<int> tp(n);
  vector<bool> onCycle(n);
  for (int t = 1; t < 4; ++t) {
    vector<vector<int>> g(n);
    vector<int> d(n);
    for (int i = 1; i < n; ++i) {
      if (fe[i] == t) {
        g[i].push_back(par[i]);
        g[par[i]].push_back(i);
        d[i]++;
        d[par[i]]++;
      }
    }
    if (t <= 2) {
      auto[u, v] = back[t - 1];
      d[u]++;
      d[v]++;
      g[u].push_back(v);
      g[v].push_back(u);
    }
    int leaf = 0;
    while (leaf < n && d[leaf] != 1) {
      leaf++;
    }
    assert(leaf < n && d[leaf] == 1);
    vector<int> path{leaf};
    while (true) {
      int cur = path.back();
      int f = -1;
      for (int v : g[cur]) {
        if (cur == leaf || v != path.end()[-2]) {
          f = v;
        }
      }
      if (f < 0) {
        break;
      }
      path.push_back(f);
    }
    assert(int(path.size()) >= 2);
    for (int v : path) {
      onCycle[v] = true;
    }
    for (int i = 1; i < int(path.size()) - 1; ++i) {
      tp[path[i]] = t;
    }
  }
  vector<int> closest(n, -1);
  queue<int> qu;
  for (int v = 0; v < n; ++v) {
    if (onCycle[v]) {
      closest[v] = v;
      qu.push(v);
    }
  }
  while (!qu.empty()) {
    int v = qu.front(); qu.pop();
    for (int u : graph[v]) {
      if (closest[u] < 0) {
        closest[u] = closest[v];
        qu.push(u);
      }
    }
  }
  while (q--) {
    int u, v;
    cin >> u >> v;
    --u, --v;
    int c[4]{};
    for (int t = 0; t < 4; ++t) {
      c[t] = GetCnt(t, u, v);
    }
    if (!total[3]) {
      //  non intersecting
      int ans = 1;
      if (c[1]) {
        ans *= 2;
      }
      if (c[2]) {
        ans *= 2;
      }
      cout << ans << '\n';
      continue;
    }
    u = closest[u];
    v = closest[v];
    if (u == v) {
      cout << 1 << '\n';
    } else if (tp[u] && tp[v] && tp[u] != tp[v]) {
      cout << 4 << '\n';
    } else {
      cout << 3 << '\n';
    }
  }

#ifdef GOLIKOV
  cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
      chrono::high_resolution_clock::now()
          - _clock_start).count() << "ms." << endl;
#endif
  return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 2ms
memory: 3492kb

input:

4 6
1 2
1 3
1 4
2 3
2 4
1 2
1 3
1 4
2 3
2 4
3 4

output:

3
3
3
3
3
4

result:

ok 6 lines

Test #2:

score: -100
Dangerous Syscalls

input:

6 4
1 2
1 3
1 6
2 3
3 4
3 5
4 5
1 2
1 3
1 4
1 6

output:


result: