結果

問題 No.3321 岩井星人グラフ-1
コンテスト
ユーザー Neculapia
提出日時 2025-11-25 10:15:15
言語 C++23
(gcc 13.3.0 + boost 1.89.0)
結果
WA  
実行時間 -
コード長 14,125 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 5,357 ms
コンパイル使用メモリ 375,592 KB
実行使用メモリ 28,744 KB
最終ジャッジ日時 2025-11-25 10:15:29
合計ジャッジ時間 13,293 ms
ジャッジサーバーID
(参考情報)
judge3 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample WA * 3
other WA * 53 TLE * 1 -- * 35
権限があれば一括ダウンロードができます
コンパイルメッセージ
main.cpp: In member function ‘void Printer::flush()’:
main.cpp:123:20: warning: ignoring return value of ‘ssize_t write(int, const void*, size_t)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
  123 |             ::write(fd, buf.data(), idx);
      |             ~~~~~~~^~~~~~~~~~~~~~~~~~~~~
main.cpp: In function ‘void solve()’:
main.cpp:181:39: warning: ‘v’ may be used uninitialized [-Wmaybe-uninitialized]
  181 |         int u, v; in.read(u, v); --u; --v;
      |                                       ^~~
main.cpp:181:16: note: ‘v’ was declared here
  181 |         int u, v; in.read(u, v); --u; --v;
      |                ^
main.cpp:159:37: warning: ‘M’ may be used uninitialized [-Wmaybe-uninitialized]
  159 | #define rep(i, n) for (i32 i = 0; i < (i32)(n); ++i)
      |                                     ^
main.cpp:180:5: note: in expansion of macro ‘rep’
  180 |     rep(i, M) {
      |     ^~~
main.cpp:176:12: note: ‘M’ was declared here
  176 |     int N, M;
      |            ^

ソースコード

diff #
raw source code

#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#include <bits/stdc++.h>
#include <unistd.h>
#include <ext/pb_ds/assoc_container.hpp>

#ifdef ATCODER
#include <atcoder/all>
#endif

using namespace std;
using namespace __gnu_pbds;
#ifdef ATCODER
using namespace atcoder;
#endif

using i32 = int;
using i64 = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
using ld = long double;
template<class T> using V = vector<T>;
template<class T> using VV = vector<V<T>>;
using pii = pair<i32, i32>;
using pll = pair<i64, i64>;
template<class T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

constexpr int INF32 = (1 << 30);
constexpr i64 INF64 = (i64(1) << 60);

struct Scanner {
    static constexpr size_t BUFSIZE = 1 << 20;
    int fd;
    size_t idx;
    size_t size;
    array<char, BUFSIZE> buf;

    Scanner(int fd_ = 0) : fd(fd_), idx(0), size(0) {}

    inline void refill() {
        size = ::read(fd, buf.data(), BUFSIZE);
        idx = 0;
    }

    inline char getch() {
        if (idx >= size) {
            refill();
            if (size == 0) return '\0';
        }
        return buf[idx++];
    }

    inline bool skip_space() {
        char c = getch();
        while (c <= ' ' && c != '\0') c = getch();
        if (c == '\0') return false;
        idx--;
        return true;
    }

    template<class T>
    bool read_signed(T &x) {
        if (!skip_space()) {
            x = 0;
            return false;
        }
        char c = getch();
        bool neg = false;
        if (c == '-') {
            neg = true;
            c = getch();
        }
        T val = 0;
        while ('0' <= c && c <= '9') {
            val = val * 10 + (c - '0');
            c = getch();
        }
        x = neg ? -val : val;
        return true;
    }

    template<class T>
    bool read_unsigned(T &x) {
        if (!skip_space()) {
            x = 0;
            return false;
        }
        char c = getch();
        T val = 0;
        while ('0' <= c && c <= '9') {
            val = val * 10 + (c - '0');
            c = getch();
        }
        x = val;
        return true;
    }

    bool read(i32 &x) { return read_signed<i32>(x); }
    bool read(i64 &x) { return read_signed<i64>(x); }
    bool read(u32 &x) { return read_unsigned<u32>(x); }
    bool read(u64 &x) { return read_unsigned<u64>(x); }
    template<class T, class U>
    bool read(T &x, U &y) { return read(x) && read(y); }
};

struct Printer {
    static constexpr size_t BUFSIZE = 1 << 20;
    int fd;
    size_t idx;
    array<char, BUFSIZE> buf;

    Printer(int fd_ = 1) : fd(fd_), idx(0) {}

    ~Printer() {
        flush();
    }

    inline void flush() {
        if (idx) {
            ::write(fd, buf.data(), idx);
            idx = 0;
        }
    }

    inline void put_char(char c) {
        if (idx == BUFSIZE) flush();
        buf[idx++] = c;
    }

    void write_str(string_view s) {
        for (char c : s) put_char(c);
    }

    template<class T>
    void print(const T &x) {
        if constexpr (is_same_v<T, string>) write_str(x);
        else if constexpr (is_integral_v<T>) {
            if (x < 0) { put_char('-'); write_unsigned(-x); }
            else write_unsigned(x);
        } else write_str("Printer Error");
        put_char('\n');
    }

    template<class T>
    void write_unsigned(T x) {
        if (x == 0) { put_char('0'); return; }
        char s[64]; int n = 0;
        while (x > 0) { s[n++] = char('0' + (x % 10)); x /= 10; }
        while (n--) put_char(s[n]);
    }
};

Scanner in;
Printer out;

#define rep(i, n) for (i32 i = 0; i < (i32)(n); ++i)
#define repi(i, a, b) for (i32 i = (i32)(a); i < (i32)(b); ++i)
#define sz(x) ((i32)(x).size())
#define all(x) begin(x), end(x)

template<class F>
struct RecLambda {
    F f;
    RecLambda(F f_) : f(move(f_)) {}
    template<class... Args>
    decltype(auto) operator()(Args &&...args) const {
        return f(*this, forward<Args>(args)...);
    }
};

// Main Solver
void solve() {
    int N, M;
    in.read(N, M);
    VV<int> adj(N);
    V<int> deg(N, 0);
    rep(i, M) {
        int u, v; in.read(u, v); --u; --v;
        adj[u].push_back(v);
        adj[v].push_back(u);
        deg[u]++; deg[v]++;
    }

    // Basic constraints check
    if (M != N - 1) { out.print("No"); return; }
    rep(i, N) if(deg[i] > 3) { out.print("No"); return; }

    int C1 = 0, C2 = 0, C3 = 0;
    rep(i, N) {
        if(deg[i] == 1) C1++;
        else if(deg[i] == 2) C2++;
        else if(deg[i] == 3) C3++;
    }

    // Helper BFS to compute distances from a set of sources
    auto bfs_multi = [&](const V<int>& sources) -> V<int> {
        V<int> d(N, -1);
        queue<int> q;
        for(int s : sources) {
            d[s] = 0; q.push(s);
        }
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int v : adj[u]){
                if(d[v] == -1){
                    d[v] = d[u] + 1;
                    q.push(v);
                }
            }
        }
        return d;
    };

    V<int> leaves, deg3s;
    rep(i, N) {
        if(deg[i] == 1) leaves.push_back(i);
        if(deg[i] == 3) deg3s.push_back(i);
    }

    V<int> min_dist_leaf = bfs_multi(leaves);
    V<int> min_dist_deg3 = bfs_multi(deg3s);

    // Group nodes by degree for fast candidate lookup
    V<V<int>> nodes_by_deg(4);
    rep(i, N) nodes_by_deg[deg[i]].push_back(i);

    // Iterate over possible Y
    // Y >= 2 because Y-1 >= 1 (distance). 
    // X = N/Y >= 3.
    for (int Y = 2; Y * 3 <= N; ++Y) {
        if (N % Y != 0) continue;
        int X = N / Y;
        
        // Target counts
        // Deg 1: X
        // Deg 2: X(Y - 2)
        // Deg 3: X
        
        int dC1 = X - C1;
        int dC2 = X * (Y - 2) - C2;
        int dC3 = X - C3;
        
        V<pii> valid_pair_types;
        rep(t1, 3) rep(t2, 3) {
            if (t1 > t2) continue;
            // simulate delta
            int c1 = 0, c2 = 0, c3 = 0;
            auto sim = [&](int t) {
                if(t == 0) c1++;
                if(t == 1) { c1--; c2++; }
                if(t == 2) { c2--; c3++; }
            };
            sim(t1); sim(t2);
            if (c1 == dC1 && c2 == dC2 && c3 == dC3) {
                valid_pair_types.push_back({t1, t2});
            }
        }
        
        if (valid_pair_types.empty()) continue;

        // Identify Bad Leaves for this Y
        V<int> bad_leaves;
        for(int l : leaves) {
            int d = min_dist_deg3[l];
            if (d == -1 || d != Y - 1) {
                bad_leaves.push_back(l);
            }
        }

        // Helper check for safety
        auto is_safe = [&](int u, int v) -> bool {
            bool u_new3 = (deg[u] == 2);
            bool v_new3 = (deg[v] == 2);
            // Check 1: New deg 3s shouldn't be too close to any leaf
            if (u_new3 && min_dist_leaf[u] != -1 && min_dist_leaf[u] < Y - 1) return false;
            if (v_new3 && min_dist_leaf[v] != -1 && min_dist_leaf[v] < Y - 1) return false;
            // Check 2: Shortcut to old deg 3
            if (min_dist_leaf[u] != -1 && min_dist_deg3[v] != -1) {
                 if (min_dist_leaf[u] + 1 + min_dist_deg3[v] < Y - 1) return false;
            }
            if (min_dist_leaf[v] != -1 && min_dist_deg3[u] != -1) {
                 if (min_dist_leaf[v] + 1 + min_dist_deg3[u] < Y - 1) return false;
            }
            // Check 3: Edge existence
            for(int x : adj[u]) if(x == v) return false;
            return true;
        };

        for(auto [t1, t2] : valid_pair_types) {
            const V<int>& U_cand = nodes_by_deg[t1];
            const V<int>& V_cand = nodes_by_deg[t2];
            if (U_cand.empty() || V_cand.empty()) continue;

            if (!bad_leaves.empty()) {
                int l = bad_leaves[0];
                V<int> dist_l = bfs_multi({l});
                V<pii> candidates;

                // Try to construct valid pairs fixing l
                // Method A: u becomes deg 3, dist(l, u) == Y - 1
                if (t1 == 2) {
                    for(int u : U_cand) {
                        if (dist_l[u] == Y - 1) {
                            if (min_dist_leaf[u] != -1 && min_dist_leaf[u] < Y - 1) continue; 
                            int limit = 0;
                            for(int v : V_cand) {
                                if (u == v) continue;
                                if (is_safe(u, v)) {
                                    candidates.push_back({u, v});
                                    if(++limit > 80) break;
                                }
                            }
                        }
                    }
                }
                // Method B: v becomes deg 3, dist(l, u) + 1 == Y - 1 -> dist(l, u) = Y - 2
                if (t2 == 2) {
                    for(int u : U_cand) {
                         if (dist_l[u] == Y - 2) {
                             int limit = 0;
                             for(int v : V_cand) {
                                 if (u == v) continue;
                                 if (is_safe(u, v)) {
                                     candidates.push_back({u, v});
                                     if(++limit > 80) break;
                                 }
                             }
                        }
                    }
                }
                // Method C: Connect to old deg 3, dist(l, u) + 1 + dist(v, deg3) == Y - 1
                for(int u : U_cand) {
                    if (dist_l[u] != -1 && dist_l[u] <= Y - 2) {
                        int rem = Y - 2 - dist_l[u];
                        int limit = 0;
                        for(int v : V_cand) {
                             if (u == v) continue;
                             if (min_dist_deg3[v] == rem) {
                                 if (is_safe(u, v)) {
                                     candidates.push_back({u, v});
                                     if (++limit > 80) break;
                                 }
                             }
                        }
                        if (candidates.size() > 500) break;
                    }
                }
                
                // Also check symmetric if t1 != t2? Handled by loop or candidates generation?
                // The above assumes u has type t1, v has type t2.
                // We also need u has type t2, v has type t1.
                if (t1 != t2) {
                     // Same logic with swapped roles
                     // Or just rely on outer loop iterating all types?
                     // Outer loop iterates t1 <= t2. So we must check swapped here or ensure logic covers it.
                     // The logic above generates candidates {u, v} where deg[u]=t1, deg[v]=t2.
                     // If we swap u,v, we get pair with deg[u]=t2, deg[v]=t1.
                     // We need to implement swapped logic too? 
                     // Actually, Method A checks if t1==2 (u becomes 3).
                     // Method B checks if t2==2 (v becomes 3).
                     // This covers asymmetrical roles.
                     // Method C iterates u in t1, v in t2.
                     // We need to also iterate u in t2, v in t1 for Method C?
                     // Yes.
                     const V<int>& U2 = nodes_by_deg[t2];
                     const V<int>& V2 = nodes_by_deg[t1];
                     
                     // Method C swapped
                     for(int u : U2) {
                        if (dist_l[u] != -1 && dist_l[u] <= Y - 2) {
                            int rem = Y - 2 - dist_l[u];
                            int limit = 0;
                            for(int v : V2) {
                                 if (u == v) continue;
                                 if (min_dist_deg3[v] == rem) {
                                     if (is_safe(u, v)) {
                                         candidates.push_back({u, v});
                                         if (++limit > 80) break;
                                     }
                                 }
                            }
                            if (candidates.size() > 500) break;
                        }
                    }
                }

                for(auto [u, v] : candidates) {
                    bool u_becomes_3 = (deg[u] == 2);
                    bool v_becomes_3 = (deg[v] == 2);
                    V<int> d_u = bfs_multi({u});
                    V<int> d_v = bfs_multi({v});
                    bool ok = true;
                    for(int bl : bad_leaves) {
                         int d_new = INF32;
                         if (min_dist_deg3[bl] != -1) d_new = min_dist_deg3[bl];
                         if (u_becomes_3 && d_u[bl] != -1) d_new = min(d_new, d_u[bl]);
                         if (v_becomes_3 && d_v[bl] != -1) d_new = min(d_new, d_v[bl]);
                         if (d_u[bl] != -1 && min_dist_deg3[v] != -1) 
                             d_new = min(d_new, d_u[bl] + 1 + min_dist_deg3[v]);
                         if (d_v[bl] != -1 && min_dist_deg3[u] != -1)
                             d_new = min(d_new, d_v[bl] + 1 + min_dist_deg3[u]);
                         if (d_new != Y - 1) { ok = false; break; }
                    }
                    if (ok) { out.print("Yes"); return; }
                }
            } else {
                // No bad leaves, just find safe pair
                int count = 0;
                for(int u : U_cand) {
                    for(int v : V_cand) {
                        if (u == v) continue;
                        if (is_safe(u, v)) {
                            out.print("Yes");
                            return;
                        }
                        if (++count > 500) break;
                    }
                    if (count > 500) break;
                }
            }
        }
    }

    out.print("No");
}

int main() {
    solve();
    return 0;
}
0