結果
問題 | No.274 The Wall |
ユーザー |
![]() |
提出日時 | 2019-07-09 23:21:10 |
言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 809 ms / 2,000 ms |
コード長 | 6,443 bytes |
コンパイル時間 | 1,172 ms |
コンパイル使用メモリ | 95,108 KB |
実行使用メモリ | 324,864 KB |
最終ジャッジ日時 | 2024-06-22 02:29:01 |
合計ジャッジ時間 | 4,091 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 22 |
ソースコード
#include <vector>#include <iostream>#include <cstdio>#include <utility>#include <tuple>#include <algorithm>using namespace std;// 移動元と行先と辺のコストを記録する構造体template <typename T = int>struct Edge {int from, to;T cost;Edge(int s, T d = 1) : to(s), cost(d) {}Edge(int f, int s, T d) : from(f), to(s), cost(d) {}bool operator<(const Edge &e) const {return cost < e.cost;}bool operator>(const Edge &e) const {return cost > e.cost;}};template <typename T = int>using Graph = vector< vector< Edge<T> > >;// 強連結成分分解// Verified: AOJ GRL_3_C (Strongly Connected Components)// Verified: ARC030 C (有向グラフ) ← 強連結を潰したグラフの構築の検証// これは 2 回の DFS によって実現できる。// はじめに普通の DFS をするが、その時に帰りがけ順に頂点番号の配列を作る。// 次に、元のグラフの逆辺のみで構成されたグラフに対して、// 帰りがけ順が遅かったものから順に DFS を行う。// 帰りかけが遅かった頂点ほど、 DAG の先頭の強連結成分に属しているため、// 辺を逆向きにすると、先頭の強連結成分から外に出られなくなることを利用している。template <typename T = int>struct GraphSCC {public:const int n;vector<bool> isthrough;vector<int> vs, cmp;vector< vector<int> > G, rG, H; // グラフ、逆辺グラフ、縮約後のグラフGraphSCC(vector< vector< Edge<T> > > &g) :n(g.size()), isthrough(n, false), cmp(n, 0), G(n), rG(n) {for(int i=0; i<n; i++) {for(size_t j=0; j<g[i].size(); j++) {G[i].push_back(g[i][j].to);rG[ g[i][j].to ].push_back(i);}}}void SCC_dfsone(int cur) {isthrough[cur] = true;for(size_t i=0; i<G[cur].size(); i++) {if(!isthrough[G[cur][i]]) {SCC_dfsone(G[cur][i]);}}vs.push_back(cur);}void SCC_dfstwo(vector<int> &vec, int cur, int k) {cmp[cur] = k;isthrough[cur] = true;vec.push_back(cur);for(size_t i=0; i<rG[cur].size(); i++) {if(!isthrough[rG[cur][i]]) {SCC_dfstwo(vec, rG[cur][i], k);}}}// 縮約後のグループ、グループ数pair<vector<int>, int> scc() {// 1回めのDFSfor(int i=0; i<n; i++)if(!isthrough[i]) SCC_dfsone(i);fill(isthrough.begin(), isthrough.end(), false);reverse(vs.begin(), vs.end());int k = 0; vector< vector<int> > S;// 2回めのDFSfor(size_t i=0; i<vs.size(); i++) {if(!isthrough[vs[i]]) {S.push_back(vector<int>());SCC_dfstwo(S.back(), vs[i], k++);}}H.resize(k);fill(isthrough.begin(), isthrough.end(), false);for(size_t i=0; i<k; i++) {for(size_t j=0; j<S[i].size(); j++) {int v = S[i][j];for(size_t x=0; x<G[v].size(); x++) {int u = G[v][x];if(isthrough[cmp[u]] || cmp[v] == cmp[u]) continue;isthrough[cmp[u]] = true;H[cmp[v]].push_back(cmp[u]);}}for(size_t j=0; j<H[i].size(); j++) isthrough[ H[i][j] ] = false;}return make_pair(cmp, k);}};// クロージャ内にあるリテラルの数が高々 2 であるときの充足可能性問題 (2-SAT)// 依存ライブラリ: SCC (graph_010_scc.cpp)struct TwoSAT {int N; Graph<> G;TwoSAT(int N_) : N(N_), G(2*N_) {}int neg(int k) { return (k+N) % (2*N); }void add_edge(int u, int v) {G[u].emplace_back(v);}void add_AorB(int a, int b) {// (a or b) -> (na => b) and (nb => a)add_edge(neg(a), b);add_edge(neg(b), a);}void add_NAorB(int a, int b) {// (na or b) -> (a => b) and (nb => na)add_edge(a, b);add_edge(neg(b), neg(a));}void add_AorNB(int a, int b) {// (a or nb) -> (na => nb) and (b => a)add_edge(neg(a), neg(b));add_edge(b, a);}void add_NAorNB(int a, int b) {// (na or nb) -> (a => nb) and (b => na)add_edge(a, neg(b));add_edge(b, neg(a));}vector<int> build() {GraphSCC<> scc(G);vector<int> group, res(N); int K;tie(group, K) = scc.scc();for(int i=0; i<N; i++) {if(group[i] == group[N+i]) return {};res[i] = (group[i] > group[N+i]);}return res;}};void yuki_274() {int N, M; scanf("%d%d", &N, &M);vector<int> L(N), R(N);auto flip = [&](int l, int r) {return make_pair(M - 1 - r, M - 1 - l);};auto intersect = [&](int al, int ar, int bl, int br) {return !(ar < bl or br < al);};for(int i=0; i<N; i++) {scanf("%d%d", &L[i], &R[i]);}TwoSAT tsat(N);for(int i=0; i<N; i++) {for(int j=i+1; j<N; j++) {for(int bit=0; bit<4; bit++) {int al = L[i], ar = R[i];int bl = L[j], br = R[j];if(bit & 1) tie(al, ar) = flip(al, ar);if(bit & 2) tie(bl, br) = flip(bl, br);if(intersect(al, ar, bl, br)) {switch(bit) {case 0:// A and B はダメ -> NA or NBtsat.add_NAorNB(i, j);break;case 1:// NA and B はダメ -> A or NBtsat.add_AorNB(i, j);break;case 2:// A and NB はダメ -> NA or Btsat.add_NAorB(i, j);break;case 3:// NA and NB はダメ -> A or Btsat.add_AorB(i, j);break;}}}}}auto res = tsat.build();if(res.size() == N) puts("YES");else puts("NO");}int main() {yuki_274();return 0;}