제출 #1195958

#제출 시각아이디문제언어결과실행 시간메모리
1195958madamadam3늑대인간 (IOI18_werewolf)C++20
0 / 100
4097 ms95424 KiB
#include "werewolf.h"
#include <bits/stdc++.h>

using namespace std;

#define FOR(i, a, b) for (int i = a; i < b; i++)
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define srt(x) sort(all(x))

typedef long long ll;
using vi = vector<int>;
using vl = vector<ll>;

struct DSU {
  int n;
  vi par, siz, fchange;
  vector<set<int>> has;
  int timer = 0;
  // vi left, right;

  DSU(int n) {
    par.assign(n, 0); iota(all(par), 0);
    siz.assign(n, 1);
    fchange.assign(n, INT_MAX);
    has.assign(n, set<int>());
    FOR(i, 0, n) has[i].insert(i);
    // left.assign(n, 1); iota(all(left), 0);
    // right.assign(n, 1); iota(all(right), 0); 
  }

  int find_set(int v, int time) {
    if (fchange[v] > time || par[v] == v) return v;
    // return par[v] = find_set(par[v]);
    return find_set(par[v], time);
  }

  void union_set(int a, int b) {
    a = find_set(a, timer);
    b = find_set(b, timer);
    if (a != b) {
      // if (siz[b] > siz[a]) swap(a, b);
      par[b] = a;
      siz[a] += siz[b];
      fchange[b] = timer++;
      // if (has[b] > has[a]) swap(has[b], has[a]);
      has[a].insert(all(has[b]));

      // left[a] = min(left[a], left[b]);
      // right[a] = min(right[a], right[b]);
    }
  }
};

/*
  N = num nodes
  X, Y = edges
  S, E = start and end nodes
  L, R = human and werewolf cities
*/

int n, m, q;
vi x, y, s, e, l, r;
vi queries;
vector<vi> adj;

bool dfs(int u, int L, int R, int target, vector<bool> &seen, bool reached_transform, bool reached_vampire) {
  // cout << "At node " << u << " L, R = (" << L << ", " << R << ") target = " << target << " RT? " << reached_transform << " RV? " << reached_vampire << "\n"; 
  if (u == target) {
    // cout << "Reached " << target << " did we transform? " << reached_transform << "\n";
    return reached_transform;
  }

  bool can = false;
  seen[u] = true;

  for (auto v : adj[u]) {
    if (seen[v]) continue;
    if (reached_vampire && v > R) continue;
    if (!reached_transform && v < L) continue;

    bool nt = reached_transform || (v >= L && v <= R);
    bool nv = reached_vampire || (v < L);
    can = can || dfs(v, L, R, target, seen, nt, nv);
    if (can) break;
  }

  seen[u] = false;
  return can;
}

int answer_query(int qn) {
  // cout << "answering query " << qn << "\n";
  int start = s[qn], end = e[qn];
  vector<bool> seen(n, false);

  return dfs(start, l[qn], r[qn], end, seen, start >= l[qn] && start <= r[qn], start < l[qn]);
}

void dfs_dp(int u, int p, vi &DP) {
  DP[u] = u;

  for (auto &v : adj[u]) {
    if (v == p) continue;
    dfs_dp(v, u, DP);
    DP[u] = max(DP[u], DP[v]);
  }
}

vi check_validity(int N, vi X, vi Y, vi S, vi E, vi L, vi R) {
  n = N; x = X; y = Y; s = S; e = E; l = L; r = R;
  m = x.size(), q = S.size();
  
  adj.assign(n, vi());
  FOR(i, 0, m) {
    adj[X[i]].pb(Y[i]);
    adj[Y[i]].pb(X[i]);
  }

  queries.assign(q, 0); iota(all(queries), 0);
  // sort(all(queries), [&](int a, int b) {return L[a] > L[b];});

  vi A(q);
  
  auto blueDSU = DSU(n);
  auto redDSU = DSU(n);
  vi wB(m), wR(m); iota(all(wB), 0); iota(all(wR), 0);
  FOR(i, 0, m) {
    wR[i] = max(X[i], Y[i]);
    wB[i] = min(X[i], Y[i]);
  }

  sort(all(wR), [&](int a, int b) {return max(X[a], Y[a]) < max(X[b], Y[b]);}); 
  sort(all(wB), [&](int a, int b) {return min(X[a], Y[a]) < min(X[b], Y[b]);}); reverse(all(wB));

  for (auto &edge : wR) {
    redDSU.union_set(X[edge], Y[edge]);
  }

  for (auto &edge : wB) {
    blueDSU.union_set(X[edge], Y[edge]);
  }

  /*
    line case:
    process queries in decreasing order of L[i]
    blueDSU 
  */
  // vi pthmax(n, INT_MIN);
  // dfs_dp(0, 0, pthmax);
  int curedge = 0;

  // for (auto query : queries) {
    // int cidx = wB[curedge];
    // while (min(X[cidx], Y[cidx]) >= L[query]) {
    //   blueDSU.union_set(X[cidx], Y[cidx]);
    //   curedge++;
    //   cidx = wB[curedge];
    // }

    // tried:
    //[1, 3, 5, 7]
    // int en = E[query]; // 1
    // int en = S[query]; // 2
    // int sn = E[query]; // 3
    // int sn = S[query]; // 4
    // int et = L[query]; // 5
    // int et = R[query]; // 6
    // int st = L[query]; // 7
    // int st = R[query]; // 8

    // for (auto en : {E, S}) {
    // for (auto sn : {E, S}) {
    // for (auto et : {L, R}) {
    // for (auto st : {L, R}) {
    // for (auto query : queries) {
    FOR(query, 0, q) {
      auto en = E;
      auto sn = S;
      auto et = R;
      auto st = L;
      set<int> s1 = redDSU.has[redDSU.find_set(en[query], et[query])];
      set<int> s2 = blueDSU.has[blueDSU.find_set(sn[query], st[query])];
      bool found = false;
      for (auto &el : s1) {
        if (s2.count(el)) {
          // cout << "1\n";
          // found = true;
          A[query] = 1;
          break;
        }
      }
      // if (!found) cout << "0\n";
    }
      // cout << "\n";
    // }}}}
  // }

  FOR(i, 0, q) A[i] = 1 - A[i];
  return A;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...