Submission #645257

#TimeUsernameProblemLanguageResultExecution timeMemory
645257Alex_tz307Colors (RMI18_colors)C++17
100 / 100
435 ms119024 KiB
#include <bits/stdc++.h>

using namespace std;

/// Observatia 1: Daca a[u] < b[u] => Nu am solutie pentru ca a poate doar sa scada, nu sa creasca.
/// La fel si pe parcurs, nu pot sa-l fac pe a[u] < b[u], pentru ca nu voi mai obtine solutie.

/// Observatia 2: Daca vreau sa fac o culoare c sa ajunga la u trebuie sa urmeze un drum astfel
/// incat pentru orice nod v din acel drum c <= a[v] si b[v] <= c(din observatia anterioara).

/// Observatia 3: Pentru ca un nod u sa fie rezolvat trebuie sa existe un nod v astfel incat
/// a[v] = b[u] si un drum de la u la v astfel incat pentru orice nod w de pe acel drum:
/// a[v] <= a[w] si b[w] <= a[v](reiese din observatiile anterioare).

/// Pornind de la aceste observatii se obtine o solutie bruta simpla: Pentru fiecare culoare c ce
/// apare in input construim un graf doar cu nodurile care satisfac proprietatea de la observatia 3
/// pentru c(c <= a[v] si b[v] <= c), iar apoi pentru toate nodurile cu b[v] = c verificam daca
/// exista un nod in componenta lor conexa astfel incat a[nod] = c.

/// Pot identifica fiecare muchie (u, v) prin 2 parametrii l si r: l = max(b[u], b[v]), r = min(a[u], a[v]).
/// => c <= r si l <= c <=> l <= c <= r. Astfel, se ajunge la un set de muchii active pentru anumite
/// intervale de timp si query-uri in privinta unor componente conexe, ceea ce se poate rezolva evident
/// cu dyanmic connectivity(offline pentru ca se stiu intervalele muchiilor de la inceput).

/// Cand am un query la momentul de timp c verific pentru toate nodurile cu b[nod] = c daca exista
/// in componenta lor un nod v astfel incat a[v] = c. Pentru asta pot marca toate componentele ce
/// contin un nod v astfel incat a[v] = c ca fiind corespunzatoare, iar apoi sa le demarchez.
/// Complexitatea amortizata a acestui pas va fi liniara, iar toata solutia va avea complexitatea
/// O(M * log^2(N)) de la dynamic connectivity(M muchii, O(log) intervale de split la intervalul
/// unei muchii si O(log) complexitatea unei operatii in DSU fara path compression).

const int kN = 1e5 + 5e4;
int a[1 + kN], b[1 + kN];
vector<int> A[1 + kN], B[1 + kN];

struct edge_t {
  int l, r, u, v;
};

struct DSU {
  vector<int> p, r, stk;
  vector<bool> mark;

  void init(int n) {
    p.resize(n + 1);
    iota(p.begin(), p.end(), 0);
    r.assign(n + 1, 1);
    mark.resize(n + 1);
  }

  int root(int x) {
    while (x != p[x]) {
      x = p[x];
    }
    return x;
  }

  void unite(int u, int v) {
    int x = root(u), y = root(v);
    if (x == y) {
      return;
    }
    if (r[y] < r[x]) {
      swap(x, y);
    }
    p[x] = y;
    r[y] += r[x];
    stk.emplace_back(x);
  }

  int currTime() {
    return stk.size();
  }

  void rollback(int checkpoint) {
    while ((int)stk.size() > checkpoint) {
      int x = stk.back();
      stk.pop_back();
      r[p[x]] -= r[x];
      p[x] = x;
    }
  }

  void update(int x, bool v) {
    mark[root(x)] = v;
  }

  bool check(int x) {
    return mark[root(x)];
  }
} dsu;

bool segIntersect(int a, int b, int c, int d) {
  return max(a, c) <= min(b, d);
}

bool solve(int l, int r, const vector<edge_t> &edges) {
  if (r < l) {
    return true;
  }
  int mid = (l + r) / 2;
  vector<edge_t> left, right;
  int checkpoint = dsu.currTime();
  for (const auto &it : edges) {
    if (it.l <= l && r <= it.r) {
      dsu.unite(it.u, it.v);
    } else {
      if (segIntersect(l, mid, it.l, it.r)) {
        left.emplace_back(it);
      }
      if (segIntersect(mid + 1, r, it.l, it.r)) {
        right.emplace_back(it);
      }
    }
  }
  if (l == r) {
    for (const int &v : A[l]) {
      dsu.update(v, true);
    }
    bool res = true;
    for (const int &v : B[l]) {
      res &= dsu.check(v);
      if (res == false) {
        break;
      }
    }
    for (const int &v : A[l]) {
      dsu.update(v, false);
    }
    dsu.rollback(checkpoint);
    return res;
  }
  bool res = solve(l, mid, left);
  if (res) {
    res = solve(mid + 1, r, right);
  }
  left.clear();
  right.clear();
  dsu.rollback(checkpoint);
  return res;
}

void testCase() {
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) {
    A[i].clear();
    B[i].clear();
  }
  for (int i = 1; i <= n; ++i) {
    cin >> a[i];
    A[a[i]].emplace_back(i);
  }
  for (int i = 1; i <= n; ++i) {
    cin >> b[i];
    B[b[i]].emplace_back(i);
  }
  vector<edge_t> edges(m);
  for (int i = 0; i < m; ++i) {
    int u, v;
    cin >> u >> v;
    edges[i] = {max(b[u], b[v]), min(a[u], a[v]), u, v};
  }
  for (int i = 1; i <= n; ++i) {
    if (a[i] < b[i]) {
      cout << "0\n";
      return;
    }
  }
  dsu.init(n);
  if (solve(1, n, edges)) {
    cout << "1\n";
  } else {
    cout << "0\n";
  }
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  int tests;
  cin >> tests;
  for (int tc = 0; tc < tests; ++tc) {
    testCase();
  }
  return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...