제출 #390252

#제출 시각아이디문제언어결과실행 시간메모리
390252Hegdahl늑대인간 (IOI18_werewolf)C++17
100 / 100
2627 ms181044 KiB
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#include "werewolf.h"
#include <bits/stdc++.h>

#define ar array

using namespace std;

struct reachability_tree {
  vector<int> boss, under, tup, time_of, lk, rk, leftmost, rightmost;

  vector<int> up[20];

  int find(int i) {
    return i == boss[i] ? i : boss[i] = find(boss[i]);
  }

  void unite(int i, int j) {
    i = find(i), j = find(j);
    if (i == j) return;

    if (under[i] < under[j]) swap(i, j);
    under[i] += under[j];
    boss[j] = i;
    tup[i] = max(tup[i], tup[j]);
  }

  int nxt_new_node;
  void add_edge(int i, int j, int t) {
    i = find(i), j = find(j);
    if (i == j) return;
    i = tup[i];
    j = tup[j];

    lk[nxt_new_node] = i;
    rk[nxt_new_node] = j;
    time_of[nxt_new_node] = t;

    unite(i, nxt_new_node);
    unite(j, nxt_new_node);

    ++nxt_new_node;
  }

  vector<int> tour, pof;
  void dfs(int cur) {
    if (lk[cur] != -1) {
      dfs(lk[cur]);
      leftmost[cur] = leftmost[lk[cur]];
      up[0][lk[cur]] = cur;
    } else leftmost[cur] = tour.size();

    pof[cur] = tour.size();
    tour.push_back(cur);
    up[0][cur] = cur;

    if (rk[cur] != -1) {
      dfs(rk[cur]);
      rightmost[cur] = rightmost[rk[cur]];
      up[0][rk[cur]] = cur;
    } else rightmost[cur] = tour.size()-1;
  }

  ar<int, 2> qry(int i, int t) {
    for (int lvl = 19; lvl >= 0; --lvl)
      if (time_of[up[lvl][i]] <= t)
        i = up[lvl][i];
    return {leftmost[i], rightmost[i]};
  }

  reachability_tree(int n, vector<ar<int, 3>> e) {
    boss.resize(2*n);
    under.resize(2*n, 1);
    tup.resize(2*n);
    time_of.resize(2*n);
    lk.resize(2*n, -1);
    rk.resize(2*n, -1);
    pof.resize(2*n, -1);
    rightmost.resize(2*n, -1);
    leftmost.resize(2*n, -1);

    iota(boss.begin(), boss.end(), 0);
    iota(tup.begin(), tup.end(), 0);

    nxt_new_node = n;

    for (auto [w, i, j] : e)
      add_edge(i, j, w);

    for (int lvl = 0; lvl < 20; ++lvl) {
      up[lvl].resize(2*n);
      iota(up[lvl].begin(), up[lvl].end(), 0);
    }

    for (int i = 0; i < 2*n; ++i)
      if (i == find(i))
        dfs(tup[i]);

    for (int lvl = 0; lvl < 19; ++lvl)
      for (int i = 0; i < 2*n; ++i)
        up[lvl+1][i] = up[lvl][up[lvl][i]];

    /*cout << "tour: ";
    for (int x : tour)
      cerr << x << ' ';
    cerr << '\n';
    cout << "pof: ";
    for (int x : pof)
      cerr << x << ' ';
    cerr << '\n';
    cout << "leftmost: ";
    for (int l : leftmost)
      cerr << l << ' ';
    cerr << '\n';
    cout << "rightmost: ";
    for (int r : rightmost)
      cerr << r << ' ';
    cerr << '\n';*/
  }
};

const int mxN = 4e5;
const int lg2 = __lg(mxN-1)+1;
const int offset = 1<<lg2;
vector<int> values[2*offset];

void insert(int i, int j) {
  i += offset;
  do {
    values[i].push_back(j);
  } while (i /= 2);
}

bool check(int I, int lo, int hi) {
  return lower_bound(values[I].begin(), values[I].end(), lo)
      != upper_bound(values[I].begin(), values[I].end(), hi);
}

bool qry(int li, int hi, int lj, int hj) {
  li += offset-1;
  hi += offset+1;

  while (li+1 < hi) {
    if (li%2 == 0) if (check(li+1, lj, hj)) return true;
    if (hi%2 == 1) if (check(hi-1, lj, hj)) return true;
    li /= 2, hi /= 2;
  }

  return false;
}

vector<int> check_validity(int n, vector<int> e0, vector<int> e1,
                                vector<int> q0, vector<int> q1,
                                vector<int> ls, vector<int> rs) {
  int m = e0.size();
  int q = q0.size();

  vector<ar<int, 3>> e(m);
  for (int mm = 0; mm < m; ++mm)
    e[mm] = {max(e0[mm], e1[mm]), e0[mm], e1[mm]};

  sort(e.begin(), e.end());
  reachability_tree lo_tree(n, e);
  for (auto &[w, i, j] : e)
    w = n-min(i, j);
  sort(e.begin(), e.end());
  reachability_tree hi_tree(n, e);

  for (int nn = 0; nn < n; ++nn) {
    int i = lo_tree.pof[nn];
    int j = hi_tree.pof[nn];
    insert(i, j);
  }

  for (int i = 2*offset-1; i > 0; --i)
    sort(values[i].begin(), values[i].end());

  vector<int> ans(q);
  for (int i = 0; i < q; ++i) {
    //cerr << '\n';
    //cerr << q0[i] << ' ' << q1[i] << ' ' << ls[i] << ' ' << rs[i] << '\n';
    auto [ll, lr] = lo_tree.qry(q1[i], rs[i]);
    auto [hl, hr] = hi_tree.qry(q0[i], n-ls[i]);

    ans[i] = qry(ll, lr, hl, hr);
  }

  return ans;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...