Submission #275152

#TimeUsernameProblemLanguageResultExecution timeMemory
275152cjoaWerewolf (IOI18_werewolf)C++11
34 / 100
1425 ms37980 KiB
#include "werewolf.h"
#include <queue>
#include <algorithm>
#include <cstdlib>
#include <cassert>
#include <iostream>

using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;

const int INF = 1000000000;
struct SegmentTree {
   int N;
   vector<int> MIN, MAX;
   SegmentTree(const vector<int>& A) {
      N = A.size();
      MIN = vector<int>(4*N);
      MAX = vector<int>(4*N);
      build(A, 1, 0, N-1);
   }
   void build(const vector<int>& A, int node, int L, int R) {
      if (L == R) {
         MIN[node] = A[L];
         MAX[node] = A[L];
         return;
      }
      int mid = (L + R)/2;
      build(A, node*2, L, mid);
      build(A, node*2+1, mid+1, R);
      MIN[node] = min(MIN[node*2], MIN[node*2+1]);
      MAX[node] = max(MAX[node*2], MAX[node*2+1]);
   }
   int query_min(int qL, int qR) {
      return query_min(qL, qR, 1, 0, N-1);
   }
   int query_min(int qL, int qR, int node, int L, int R) {
      if (qR < L || qL > R) return +INF;
      if (qL <= L && R <= qR) return MIN[node];
      int mid = (L + R)/2;
      return min(query_min(qL, qR, node*2, L, mid),
                 query_min(qL, qR, node*2+1, mid+1, R));
   }
   int query_max(int qL, int qR) {
      return query_max(qL, qR, 1, 0, N-1);
   }
   int query_max(int qL, int qR, int node, int L, int R) {
      if (qR < L || qL > R) return -INF;
      if (qL <= L && R <= qR) return MAX[node];
      int mid = (L + R)/2;
      return max(query_max(qL, qR, node*2, L, mid),
                 query_max(qL, qR, node*2+1, mid+1, R));
   }
};

VVI get_graph(int N, const VI& X, const VI& Y) {
   VVI G(N);
   int M = X.size();
   for (int j = 0; j < M; ++j) {
      int u = X[j], v = Y[j];
      G[u].push_back(v);
      G[v].push_back(u);
   }
   return G;
}

VI bfs(int N, VVI& adj, int src, int dst) {
   queue<int> q;
   q.push(src);
   VI D(N, INF);
   D[src] = 0;
   VI P(N, -1);
   while (!q.empty()) {
      int u = q.front(); q.pop();
      if (u == dst) {
         VI path;
         for (int x = dst; x >= 0; x = P[x])
            path.push_back(x);
         reverse(path.begin(), path.end());
         return path;
      }
      for (int v : adj[u]) {
         if (D[v] > D[u] + 1) {
            D[v] = D[u] + 1;
            P[v] = u;
            q.push(v);
         }
      }
   }
   return {};
}

bool is_subtask3(int N, int M, VVI& adj, VI& line) {
   if (M != N-1)
      return false;

   VI nodes_deg1;
   for (int u = 0; u < N; ++u) {
      if (adj[u].size() > 2)
         return false;
      if (adj[u].size() == 1)
         nodes_deg1.push_back(u);
   }
   assert(nodes_deg1.size() == 2);
   
   line = bfs(N, adj, nodes_deg1[0], nodes_deg1[1]);
   assert(line.size() == N);

   return true;
}

bool query(SegmentTree& st, const VI& line, const VI& pos,
           int src, int dst, int L, int R) {
   int src_pos = pos[src], dst_pos = pos[dst];
   if (src_pos < dst_pos) {
      // de izquierda a derecha

      if (st.query_min(src_pos, dst_pos) >= L)
         return true;

      // binary search para encontrar el primer nodo (a la derecha de src_pos)
      // mas pequenio que L
      int lo = src_pos, hi = dst_pos;
      int m = -1;
      while (lo <= hi) {
         int mid = (lo + hi) / 2;
         int cur = st.query_min(lo, mid);
         if (cur < L) {
            m = mid;
            hi = mid-1;
         }
         else {
            lo = mid+1;
         }
      }

      assert(m != -1 && m > src_pos);
      assert(line[m-1] >= L);

      // m es la posicion del primer nodo mas pequenio que L
      if (line[m-1] > R)
         return false;

      if (st.query_max(m, dst_pos) > R)
         return false;

   }
   else {
      // de derecha a izquierda

      if (st.query_min(dst_pos, src_pos) >= L)
         return true;

      // binary search para encontrar el primer nodo (a la izquierda de src_pos)
      // mas pequenio que L
      int lo = dst_pos, hi = src_pos;
      int m = -1;
      while (lo <= hi) {
         int mid = (lo + hi) / 2;
         if (st.query_min(mid, hi) < L) {
            m = mid;
            lo = mid+1;
         }
         else {
            hi = mid-1;
         }
      }
      assert(m != -1 && m < src_pos);
      assert(line[m+1] >= L);

      // m es la posicion del primer nodo mas pequenio que L
      if (line[m+1] > R)
         return false;

      if (st.query_max(dst_pos, m) > R)
         return false;
   }

   
   return true;
}

std::vector<int> check_validity(int N, std::vector<int> X, std::vector<int> Y,
                                std::vector<int> S, std::vector<int> E,
                                std::vector<int> L, std::vector<int> R) {
   

   int Q = S.size();
   std::vector<int> res(Q);

   VVI adj = get_graph(N, X, Y);

   VI line;
   if (is_subtask3(N, X.size(), adj, line)) {
      VI pos(N);
      for (int i = 0; i < N; ++i) {
         int u = line[i];
         pos[u] = i;
      }
      SegmentTree st(line);
      for (int q = 0; q < Q; ++q) {
         res[q] = query(st, line, pos, S[q], E[q], L[q], R[q]);
      }
      return res;
   }

   for (int i = 0; i < Q; ++i) {
      res[i] = rand() % 2;
   }
   return res;
}

Compilation message (stderr)

In file included from /usr/include/c++/9/cassert:44,
                 from werewolf.cpp:5:
werewolf.cpp: In function 'bool is_subtask3(int, int, VVI&, VI&)':
werewolf.cpp:108:23: warning: comparison of integer expressions of different signedness: 'std::vector<int>::size_type' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
  108 |    assert(line.size() == N);
      |           ~~~~~~~~~~~~^~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...