제출 #1356481

#제출 시각아이디문제언어결과실행 시간메모리
1356481Numberz늑대인간 (IOI18_werewolf)C++20
100 / 100
565 ms138272 KiB
#include "werewolf.h"
#include <bits/stdc++.h>
using namespace std;
#define ll long long

int lg = 20;

struct segtree {

  vector<int> tree;
  segtree(int n) : tree(4*n) {}

  void update(int i, int x, int l, int r, int node) {
    if (l == r) tree[node] += x;
    else {
      int m = (l + r) / 2;
      if (i <= m) update(i, x, l, m, node<<1);
      else update(i, x, m+1, r, node<<1|1);
      tree[node] = tree[node<<1] + tree[node<<1|1];
    }
  }

  int qry(int ql, int qr, int l, int r, int node) {
    if (ql <= l && r <= qr) return tree[node];
    if (r < ql || qr < l) return 0;
    int m = (l + r) / 2;
    return qry(ql, qr, l, m, node<<1) + qry(ql, qr, m+1, r, node<<1|1);
  }

};

struct dsu {

  vector<int> id, sz;
  dsu(int n) {
    for (int i = 0; i < n; i++) {
      id.push_back(i);
      sz.push_back(1);
    }
  }

  int find(int x) {return x == id[x] ? x : id[x] = find(id[x]);}

  void unite(int a, int b) {
    a = find(a), b = find(b);
    if (a==b) return;
    sz[a] += sz[b];
    id[b] = a;
  }

};

vector<int> check_validity(int N, vector<int> X, vector<int> Y, vector<int> S, vector<int> E, vector<int> L, vector<int> R) {
  
  //make bigtree and smalltree
  int M = X.size();
  vector<vector<int>> totadj(N+1), adjsmall(N+1), adjbig(N+1), parsmall(lg, vector<int>(N, -1)), parbig(lg, vector<int>(N, -1));
  dsu smalltree(N), bigtree(N);
  for (int i = 0; i < M; i++) {
    totadj[X[i]].push_back(Y[i]);
    totadj[Y[i]].push_back(X[i]);
  }

  for (int i = 0; i < N; i++) for (int u : totadj[i]) if (u < i) {
    int uu = smalltree.find(u);
    if (i == uu) continue;
    smalltree.unite(i, uu);
    parsmall[0][uu] = i;
    adjsmall[i].push_back(uu);
  }

  for (int i = N-1; i >= 0; i--) for (int u : totadj[i]) if (u > i) {
    int uu = bigtree.find(u);
    if (i == uu) continue;
    bigtree.unite(i, uu);
    parbig[0][uu] = i;
    adjbig[i].push_back(uu);
  }


  //Now find dfsorder for both trees + BinaryLifting ready
  vector<int> smallorder = {0}, bigorder = {0}, possmall(N, 0), posbig(N, 0), subbig(N, 0), subsmall(N, 0), Lsmall(N), Lbig(N), Rsmall(N), Rbig(N);
  for (int b = 1; b < lg; b++) for (int i = 0; i < N; i++) {
    if (parsmall[b-1][i] != -1) parsmall[b][i] = parsmall[b-1][parsmall[b-1][i]];
    if (parbig[b-1][i] != -1) parbig[b][i] = parbig[b-1][parbig[b-1][i]];
  }

  auto dfs = [&](int node, int tp, auto& dfs) -> void {
    if (tp == 0) {
      subsmall[node] = 1;
      possmall[node] = smallorder.size();
      smallorder.push_back(node);
      Lsmall[node] = possmall[node];
      for (int u : adjsmall[node]) {
        dfs(u, tp, dfs);
        subsmall[node] += subsmall[u];
      }
      Rsmall[node] = Lsmall[node] + subsmall[node] - 1;
    } else {
      subbig[node] = 1;
      posbig[node] = bigorder.size();
      bigorder.push_back(node);
      Lbig[node] = posbig[node];
      for (int u : adjbig[node]) {
        dfs(u, tp, dfs);
        subbig[node] += subbig[u];
      }
      Rbig[node] = Lbig[node] + subbig[node] - 1;
    }
  };

  for (int i = 0; i < N; i++) {
    if (!subsmall[i]) {
      int root = i;
      for (int b = lg-1; b >= 0; b--) {
        if (parsmall[b][root] != -1) root = parsmall[b][root];
      }
      dfs(root, 0, dfs);
    } 
    if (!subbig[i]) {
      int root = i;
      for (int b = lg-1; b >= 0; b--) if (parbig[b][root] != -1) root = parbig[b][root];
      dfs(root, 1, dfs);
    }
  }


  // Now we want to maintain a segmenttree
  //we consider for each int 0 - n-1 the coordinates possmall, posbig
  int Q = S.size();
  vector<int> res(Q, 0);
  vector<vector<vector<int>>> Lqrys(N+1), Rqrys(N+1);
  for (int i = 0; i < Q; i++) {

    int root1 = S[i], root2 = E[i];
    //starting at S, we can only take nodes <= R
    for (int b = lg-1; b >= 0; b--) {
      if (parsmall[b][root2] != -1 && parsmall[b][root2] <= R[i]) root2 = parsmall[b][root2];
      if (parbig[b][root1] != -1 && parbig[b][root1] >= L[i]) root1 = parbig[b][root1];
    }

    //so now we have our two roots, and for each we also have
    //each query is { L, R, idx }
    Lqrys[Lsmall[root2]].push_back({Lbig[root1], Rbig[root1], i});
    Rqrys[Rsmall[root2]].push_back({Lbig[root1], Rbig[root1], i});

  }


  segtree seg(N);
  for (int i = 1; i <= N; i++) {
    //first answer all lefts
    for (auto& v : Lqrys[i]) res[v[2]] -= seg.qry(v[0], v[1], 1, N, 1);
    //then update our val
    seg.update(posbig[smallorder[i]], 1, 1, N, 1);
    //Now finish right queries
    for (auto& v : Rqrys[i]) res[v[2]] += seg.qry(v[0], v[1], 1, N, 1);
  }

  for (int i = 0; i < Q; i++) res[i] = res[i] > 0;

  return res;

}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…