Submission #1197005

#TimeUsernameProblemLanguageResultExecution timeMemory
1197005madamadam3Werewolf (IOI18_werewolf)C++20
100 / 100
1330 ms203960 KiB
#include "werewolf.h"
#include <bits/stdc++.h>

using namespace std;

#define FOR(i, a, b) for (int i = a; i < b; i++)
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define srt(x) sort(all(x))

typedef long long ll;
using vi = vector<int>;
using vl = vector<ll>;

struct Edge {
    int u, v, w;

    bool operator<(const Edge &other) const {
        return w < other.w;
    }
};

// we need dsu to find the root of node u's current component
struct DSU {
    int n;
    vector<int> par, size;

    DSU(int N) {
        n = N;
        par.assign(n, 0); iota(par.begin(), par.end(), 0);
        size.assign(n, 1); 
    }

    DSU() : n(0) {};

    int find_set(int v) {
        if (par[v] == v) {
            return v;
        }

        return par[v] = find_set(par[v]);
    }

    void unite(int a, int b) {
        a = find_set(a);
        b = find_set(b);

        if (a != b) {
            // if (size[a] < size[b]) swap(a, b); // no union by rank though 
            par[b] = a;
            size[a] += size[b];
        }
    }
};

struct DSUTree {
    int n, m, k; // n = original graph size, m = num edges, k = 2n-1 = kruskal tree size
    DSU dsu;
    vector<vector<int>> adj; // adjlist for dsu tree
    vector<int> value, edgeid; // value of node i (0 for all leaves)
    vector<Edge> edge_list;

    int MAXLOG;
    vector<vector<int>> up;
    int timer;
    vector<int> tin, tout;

    DSUTree(int N, vector<Edge> edges) {
        n = N;
        m = edges.size();
        k = 2 * n - 1;
        edge_list = edges;
        dsu = DSU(k);

        adj.assign(k, vector<int>());
        value.assign(k, 0);
        edgeid.assign(k, 0);

        construct();
    }   

    void dfs(int u, int p) {
        tin[u] = timer++;
        up[u][0] = p;
        for (int i = 1; i < MAXLOG; i++) {
            up[u][i] = up[up[u][i - 1]][i - 1];
        }

        for (auto &v : adj[u]) {
            if (v == p) continue;
            dfs(v, u);
        }

        tout[u] = timer;
    }

    void construct() {
        sort(edge_list.begin(), edge_list.end());
        int cur_anc = n; // who shall we set the ancestor of u and v to for the current merge

        for (int i = 0; i < m; i++) {
            Edge cur = edge_list[i];
            int u = cur.u, v = cur.v, w = cur.w;
            int uhead = dsu.find_set(u), vhead = dsu.find_set(v);

            if (uhead != vhead) {
                dsu.unite(cur_anc, uhead);
                dsu.unite(cur_anc, vhead);

                adj[cur_anc].push_back(uhead);
                adj[cur_anc].push_back(vhead);
                adj[uhead].push_back(cur_anc);
                adj[vhead].push_back(cur_anc);

                value[cur_anc] = w;
                edgeid[cur_anc] = i;
                cur_anc++;
            }
        }

        MAXLOG = 0;
        while (k >= (1 << MAXLOG)) MAXLOG++;

        up.assign(k, vector<int>(MAXLOG, 0));
        tin.assign(k, 0);
        tout.assign(k, 0);
        timer = 0;
        dfs(dsu.find_set(0), dsu.find_set(0));
    }

    bool is_ancestor(int u, int v) {
        return tin[u] <= tin[v] && tout[u] >= tout[v];
    }

    int lca(int u, int v) {
        if (is_ancestor(u, v)) return u;
        if (is_ancestor(v, u)) return v;

        for (int i = MAXLOG - 1; i >= 0; i++) {
            if (!is_ancestor(up[u][i], v)) u = up[u][i];
        }

        return up[u][0];
    }

    int query_pathmax(int u, int v) { // max edge on path from u to v 
        int anc = lca(u, v);
        return value[anc];
    }

    bool can_reach(int u, int v, int x) { // can i reach v from u in first x nodes
        return edgeid[lca(u, v)] < x;
    }
};

struct Node {
    Node *left, *right;
    int sum;

    Node(int val) : left(nullptr), right(nullptr), sum(val) {};

    Node(Node* L, Node* R) {
        left = L;
        right = R;
        sum = 0;

        if (left) sum += left->sum;
        if (right) sum += right->sum; 
    }
};

struct SegTree {
    int n;
    vector<Node*> roots;
    vector<int> arr;

    Node* build(int l, int r) {
        if (l + 1 == r) return new Node(arr[l]);

        int m = l + (r - l) / 2;
        return new Node(build(l, m), build(m, r));
    }

    Node* update(Node *current, int l, int r, int k, int v) {
        if (!(l <= k && k < r)) return current;
        if (l + 1 == r) return new Node(v);

        int m = l + (r - l) / 2;
        return new Node(update(current->left, l, m, k, v), update(current->right, m, r, k, v));
    }

    int query(Node *current, int l, int r, int ql, int qr) {
        if (r <= ql || qr <= l) return 0;
        if (ql <= l && r <= qr) return current->sum;

        int m = l + (r - l) / 2;
        return query(current->left, l, m, ql, qr) + query(current->right, m, r, ql, qr);
    }

    void update(int k, int v) {
        roots.push_back(update(roots.back(), 0, n, k, v));
    }

    int query(int l, int r, int time) {
        return query(roots[time], 0, n, l, r);
    }

    SegTree(int n, vector<int> arr) {
        this->n = n;
        this->arr = arr;

        roots.push_back(build(0, n));
    }
};

/*
  N = num nodes
  X, Y = edges
  S, E = start and end nodes
  L, R = human and werewolf cities
*/

int n, m, q;
vi x, y, s, e, l, r;

vi check_validity(int N, vi X, vi Y, vi S, vi E, vi L, vi R) {
    int n = N, m = X.size(), q = S.size();
    // 1) Build two KRTs:
    //    DLo for “≤ R” uses w = max(u,v)
    //    DHi for “≥ L” uses w = -min(u,v)
    vector<Edge> edges_lo(m), edges_hi(m);
    FOR(i,0,m) {
        int u = X[i], v = Y[i];
        edges_lo[i] = {u, v, max(u,v)};
        edges_hi[i] = {u, v, -min(u,v)};
    }
    DSUTree DLo(n, edges_lo);
    DSUTree DHi(n, edges_hi);

    int K = 2*n - 1;
    auto &tin_lo  = DLo.tin;
    auto &tout_lo = DLo.tout;
    auto &tin_hi  = DHi.tin;
    auto &tout_hi = DHi.tout;

    // 2) Collect each city as a point (x = tin_hi, y = tin_lo)
    vector<pair<int,int>> pts(n);
    FOR(i,0,n) pts[i] = { tin_hi[i], tin_lo[i] };
    sort(all(pts));

    // 3) Build events: for each query we need to test if
    //    any point lies in [a,b)×[c,d).  We'll do two events
    //    at x=b-1 (+1) and x=a-1 (−1).
    struct Event { int x, y1, y2, idx, sign; };
    vector<Event> events; events.reserve(2*q);

    FOR(i,0,q) {
        int Si = S[i], Ei = E[i], Li = L[i], Ri = R[i];

        // climb DHi so that all merges along S→u have w ≤ -L  ⇔  min(vertex) ≥ L
        int thresh_hi = -Li;
        int u = Si;
        for (int d = DHi.MAXLOG-1; d >= 0; d--) {
            int vup = DHi.up[u][d];
            if (DHi.value[vup] <= thresh_hi) u = vup;
        }
        int a = tin_hi[u], b = tout_hi[u];

        // climb DLo so that all merges along E→v have w ≤ R  ⇔  max(vertex) ≤ R
        int thresh_lo = Ri;
        int v = Ei;
        for (int d = DLo.MAXLOG-1; d >= 0; d--) {
            int vup = DLo.up[v][d];
            if (DLo.value[vup] <= thresh_lo) v = vup;
        }
        int c = tin_lo[v], d2 = tout_lo[v];

        events.push_back({b-1, c, d2, i, +1});
        events.push_back({a-1, c, d2, i, -1});
    }
    sort(all(events), [&](auto &A, auto &B){ return A.x < B.x; });

    // 4) Fenwick tree over y in [0..K)
    vector<int> bit(K+1, 0);
    auto bit_add = [&](int pos, int v) {
        for (int i = pos+1; i <= K; i += i&-i)
            bit[i] += v;
    };
    auto bit_sum = [&](int pos) {
        int s = 0;
        for (int i = pos; i > 0; i -= i&-i)
            s += bit[i];
        return s;
    };
    auto bit_range = [&](int lpos, int rpos) {
        if (lpos >= rpos) return 0;
        return bit_sum(rpos) - bit_sum(lpos);
    };

    // 5) Sweep
    vi acc(q, 0);
    int ptr = 0;
    for (auto &ev : events) {
        // add all points with x ≤ ev.x
        while (ptr < n && pts[ptr].first <= ev.x) {
            bit_add(pts[ptr].second, +1);
            ptr++;
        }
        int cnt = bit_range(ev.y1, ev.y2);
        acc[ev.idx] += ev.sign * cnt;
    }

    // 6) any positive → reachable
    vi ans(q);
    FOR(i,0,q) ans[i] = (acc[i] > 0);
    return ans;
}

#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...