답안 #549012

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
549012 2022-04-15T00:35:17 Z SmolBrain Usmjeri (COCI17_usmjeri) C++17
28 / 140
2000 ms 109612 KB
// Om Namah Shivaya
// GM in 110 days

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

typedef long long int ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

#define fastio ios_base::sync_with_stdio(false); cin.tie(NULL)
#define endl '\n'
#define pb push_back
#define conts continue
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define yes cout << "YES" << endl
#define no cout << "NO" << endl
#define ff first
#define ss second
#define ceil2(x,y) ((x+y-1) / (y))
#define sz(a) a.size()
#define setbits(x) __builtin_popcountll(x)
#ifndef ONLINE_JUDGE
#define debug(x) cout << #x <<" = "; print(x); cout << endl
#else
#define debug(x)
#endif

#define rep(i,n) for(int i = 0; i < n; ++i)
#define rep1(i,n) for(int i = 1; i <= n; ++i)
#define rev(i,s,e) for(int i = s; i >= e; --i)
#define trav(i,a) for(auto &i : a)

bool iseven(ll n) {if ((n & 1) == 0) return true; return false;}

void print(ll t) {cout << t;}
void print(int t) {cout << t;}
void print(string t) {cout << t;}
void print(char t) {cout << t;}
void print(double t) {cout << t;}
void print(ld t) {cout << t;}

template <class T, class V> void print(pair <T, V> p);
template <class T> void print(vector <T> v);
template <class T> void print(set <T> v);
template <class T, class V> void print(map <T, V> v);
template <class T> void print(multiset <T> v);
template <class T, class V> void print(pair <T, V> p) {cout << "{"; print(p.ff); cout << ","; print(p.ss); cout << "}";}
template <class T> void print(vector <T> v) {cout << "[ "; for (T i : v) {print(i); cout << " ";} cout << "]";}
template <class T> void print(set <T> v) {cout << "[ "; for (T i : v) {print(i); cout << " ";} cout << "]";}
template <class T> void print(multiset <T> v) {cout << "[ "; for (T i : v) {print(i); cout << " ";} cout << "]";}
template <class T, class V> void print(map <T, V> v) {cout << "[ "; for (auto i : v) {print(i); cout << " ";} cout << "]";}
template<typename T> void amin(T &a, T b) { a = min(a, b); }
template<typename T> void amax(T &a, T b) { a = max(a, b); }

void usaco(string filename) {
    freopen((filename + ".in").c_str(), "r", stdin);
    freopen((filename + ".out").c_str(), "w", stdout);
}

const int MOD = 1e9 + 7;
const int maxn = 3e5 + 5;
const int inf1 = 1e9 + 5;
const ll inf2 = ll(1e18) + 5;

template<typename T>
struct lazysegtree {
    /*=======================================================*/

    struct data {
        ll one, two;
    };

    struct lazy {
        ll a;
    };

    data d_neutral = {0, 0};
    lazy l_neutral = {0};

    void merge(data &curr, data &left, data &right) {
        curr.one = left.one + right.one;
        curr.two = left.two + right.two;
    }

    void create(int x, int lx, int rx, T v) {

    }

    void modify(int x, int lx, int rx, T v) {
        lz[x].a = v;
    }

    void propagate(int x, int lx, int rx) {
        ll val = lz[x].a;
        if (val == 0) return;

        ll len = rx - lx;

        if (val == 1) tr[x] = {len, 0};
        else tr[x] = {0, len};

        if (rx - lx > 1) {
            lz[2 * x + 1].a = val;
            lz[2 * x + 2].a = val;
        }

        lz[x] = l_neutral;
    }

    /*=======================================================*/

    int siz = 1;
    vector<data> tr;
    vector<lazy> lz;

    lazysegtree() {

    }

    lazysegtree(int n) {
        while (siz < n) siz *= 2;
        tr.assign(2 * siz, d_neutral);
        lz.assign(2 * siz, l_neutral);
    }

    void build(vector<T> &a, int n, int x, int lx, int rx) {
        if (rx - lx == 1) {
            if (lx < n) {
                create(x, lx, rx, a[lx]);
            }

            return;
        }

        int mid = (lx + rx) / 2;

        build(a, n, 2 * x + 1, lx, mid);
        build(a, n, 2 * x + 2, mid, rx);

        merge(tr[x], tr[2 * x + 1], tr[2 * x + 2]);
    }

    void build(vector<T> &a, int n) {
        build(a, n, 0, 0, siz);
    }

    void rupd(int l, int r, T v, int x, int lx, int rx) {
        propagate(x, lx, rx);

        if (lx >= r or rx <= l) return;
        if (lx >= l and rx <= r) {
            modify(x, lx, rx, v);
            propagate(x, lx, rx);
            return;
        }

        int mid = (lx + rx) / 2;

        rupd(l, r, v, 2 * x + 1, lx, mid);
        rupd(l, r, v, 2 * x + 2, mid, rx);

        merge(tr[x], tr[2 * x + 1], tr[2 * x + 2]);
    }

    void rupd(int l, int r, T v) {
        rupd(l, r + 1, v, 0, 0, siz);
    }

    data query(int l, int r, int x, int lx, int rx) {
        propagate(x, lx, rx);

        if (lx >= r or rx <= l) return d_neutral;
        if (lx >= l and rx <= r) return tr[x];

        int mid = (lx + rx) / 2;

        data curr;
        data left = query(l, r, 2 * x + 1, lx, mid);
        data right = query(l, r, 2 * x + 2, mid, rx);

        merge(curr, left, right);
        return curr;
    }

    data query(int l, int r) {
        return query(l, r + 1, 0, 0, siz);
    }
};

lazysegtree<int> st;

vector<int> adj[maxn];

struct lca_algo {
    // LCA template (for graphs with 1-based indexing)

    int LOG = 1;
    vector<int> depth;
    vector<vector<int>> up;

    lca_algo() {

    }

    lca_algo(int n) {
        lca_init(n);
    }

    void lca_init(int n) {
        while ((1 << LOG) < n) LOG++;
        up = vector<vector<int>>(n + 1, vector<int>(LOG, 1));
        depth = vector<int>(n + 1);

        lca_dfs(1, -1);
    }

    void lca_dfs(int node, int par) {
        trav(child, adj[node]) {
            if (child == par) conts;

            up[child][0] = node;
            rep1(j, LOG - 1) {
                up[child][j] = up[up[child][j - 1]][j - 1];
            }

            depth[child] = depth[node] + 1;

            lca_dfs(child, node);
        }
    }

    int lift(int u, int k) {
        rep(j, LOG) {
            if (k & (1 << j)) {
                u = up[u][j];
            }
        }

        return u;
    }

    int query(int u, int v) {
        if (depth[u] < depth[v]) swap(u, v);
        int k = depth[u] - depth[v];
        u = lift(u, k);

        if (u == v) return u;

        rev(j, LOG - 1, 0) {
            if (up[u][j] != up[v][j]) {
                u = up[u][j];
                v = up[v][j];
            }
        }

        u = up[u][0];
        return u;
    }
};

lca_algo LCA;
vector<int> parent(maxn, -1), depth(maxn), heavy(maxn, -1), head(maxn, -1), nodepos(maxn);
int cntr = 1;

int dfs(int node, int par) {
    int currsiz = 1, mxsiz = -1;

    trav(child, adj[node]) {
        if (child == par) conts;

        parent[child] = node;
        depth[child] = depth[node] + 1;

        int childsiz = dfs(child, node);
        currsiz += childsiz;

        if (childsiz > mxsiz) {
            mxsiz = childsiz;
            heavy[node] = child;
        }
    }

    return currsiz;
}

void decompose(int node, int par, int leader) {
    head[node] = leader;
    nodepos[node] = cntr++;

    if (heavy[node] != -1) {
        decompose(heavy[node], node, leader);
    }

    trav(child, adj[node]) {
        if (child == par or child == heavy[node]) conts;

        decompose(child, node, child);
    }
}

void rupd(int u, int v, int val) {
    for (; head[u] != head[v]; v = parent[head[v]]) {
        if (depth[head[u]] > depth[head[v]]) swap(u, v);

        st.rupd(nodepos[head[v]], nodepos[v], val);
    }

    if (depth[u] > depth[v]) swap(u, v);
    st.rupd(nodepos[u] + 1, nodepos[v], val);
}

pii query(int u, int v) {
    int one = 0, two = 0;

    for (; head[u] != head[v]; v = parent[head[v]]) {
        if (depth[head[u]] > depth[head[v]]) swap(u, v);

        auto [val1, val2] = st.query(nodepos[head[v]], nodepos[v]);
        one += val1, two += val2;
    }

    if (depth[u] > depth[v]) swap(u, v);

    auto [val1, val2] = st.query(nodepos[u] + 1, nodepos[v]);
    one += val1, two += val2;

    return {one, two};
}

void solve(int test_case)
{
    /*

    personal notes:
    had to stress test my code with an ac solution to find the bug
    ac solution used: https://oj.uz/submission/520832 , thanks to tube5429 (the author of the ac solution used)

    */

    int n, m; cin >> n >> m;
    rep1(i, n - 1) {
        int u, v; cin >> u >> v;
        adj[u].pb(v), adj[v].pb(u);
    }

    st = lazysegtree<int>(n + 5);

    dfs(1, -1);
    decompose(1, -1, 1);

    LCA = lca_algo(n);

    auto get_dis = [&](int u, int v) {
        int lca = LCA.query(u, v);
        return depth[u] + depth[v] - 2 * depth[lca];
    };

    int ans = 1;

    vector<pii> queries(m);

    rep(i, m) {
        int u, v; cin >> u >> v;
        queries[i] = {u, v};
    }

    auto comp = [&](pii p1, pii p2) {
        int dis1 = get_dis(p1.ff, p1.ss);
        int dis2 = get_dis(p2.ff, p2.ss);

        return dis1 > dis2;
    };

    sort(all(queries), comp);

    for (auto [u, v] : queries) {
        if (depth[u] > depth[v]) swap(u, v);
        int lca = LCA.query(u, v);

        auto [one1, two1] = query(u, lca);
        auto [one2, two2] = query(v, lca);

        if (one1 == 0 and two1 == 0 and one2 == 0 and two2 == 0) {
            ans = (ans * 2) % MOD;
            rupd(u, lca, 1);
            rupd(v, lca, 2);
        }
        else {
            if (u == lca) {
                int cnt = (one1 > 0) + (two1 > 0) + (one2 > 0) + (two2 > 0);
                if (cnt > 1) {
                    cout << 0 << endl;
                    return;
                }
            }

            if ((one1 and one2) or (two1 and two2)) {
                cout << 0 << endl;
                return;
            }

            if (one1 or two2) {
                rupd(u, lca, 1);
                rupd(v, lca, 2);
            }
            else {
                rupd(u, lca, 2);
                rupd(v, lca, 1);
            }
        }
    }

    rep1(u, n) {
        trav(v, adj[u]) {
            if (u != parent[v]) conts;

            int lca = u;

            auto [one, two] = query(v, lca);

            if (one == 0 and two == 0) {
                ans = (ans * 2) % MOD;
            }
        }
    }

    cout << ans << endl;
}

int main()
{
    fastio;

    int t = 1;
    // cin >> t;
    rep1(i, t) {
        solve(i);
    }

    return 0;
}

Compilation message

usmjeri.cpp: In function 'void usaco(std::string)':
usmjeri.cpp:64:12: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
   64 |     freopen((filename + ".in").c_str(), "r", stdin);
      |     ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
usmjeri.cpp:65:12: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
   65 |     freopen((filename + ".out").c_str(), "w", stdout);
      |     ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# 결과 실행 시간 메모리 Grader output
1 Correct 1058 ms 42700 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 1830 ms 109612 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Incorrect 8 ms 13396 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 10 ms 13524 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 21 ms 14352 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 14 ms 14372 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Execution timed out 2071 ms 86700 KB Time limit exceeded
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Execution timed out 2080 ms 86756 KB Time limit exceeded
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Execution timed out 2088 ms 87044 KB Time limit exceeded
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Execution timed out 2101 ms 87196 KB Time limit exceeded
2 Halted 0 ms 0 KB -