Submission #155184

#TimeUsernameProblemLanguageResultExecution timeMemory
155184rama_pangWerewolf (IOI18_werewolf)C++14
0 / 100
941 ms129680 KiB
#include "werewolf.h"
#include <bits/stdc++.h>
using namespace std;

struct disj {
    vector<int> p;
    disj(int n) {
        p.resize(n);
        iota(p.begin(), p.end(), 0);
    }
    int par(int n) {
        return (p[n] == n)? n : p[n] = par(p[n]);
    }
};

struct graph {
    vector<vector<int>> G;
    graph(int n) {
        G.resize(n);
    }
    inline void add_edge(int a, int b) {
        G[a].emplace_back(b);
    }
    void dfs(int n, int p, vector<pair<int, int>> &euler_tour, vector<int> &euler) {
        euler_tour[n].first = euler.size();
        euler.emplace_back(n);
        for (auto &i : G[n]) if (i != p) {
            dfs(i, n, euler_tour, euler);
        }
        euler_tour[n].second = euler.size() - 1;
    }
};


struct solver {
    struct event {
        int x, y1, y2, type, idx;
        bool operator < (const event &b) const {
            return x < b.x || (x == b.x && type < b.type);
        }   
    };
    struct bit {
        vector<int> tree;
        bit() {}
        bit(int n) {
            tree.resize(n + 1);
        }
        void init(int n) {
            tree.assign(n + 1, 0);
        }
        void upd(int n, int x) {
            for (int i = n + 1; i < tree.size(); i += i & -i) {
                tree[i] += x;
            }
        }
        int ask(int n) {
            int res = 0;
            for (int i = n + 1; i > 0; i -= i & -i) {
                res += tree[i];
            }
            return res;
        }
    };
    vector<event> e;
    bit bt;
    solver(int n) {
        bt.init(n);
    }
    inline void add_point(int x, int y) {
        e.push_back({x, y, -1, 0, -1}); //add point
    }
    inline void add_query(int x1, int x2, int y1, int y2, int id) {
        e.push_back({x1, y1, y2, -1, id}); //add
        e.push_back({x2, y1, y2, +1, id}); //remove
    }
    void line_sweep(vector<int> &res) {
        sort(e.begin(), e.end());
        for (auto &k : e) {
            if (k.type == -1) {
                res[k.idx] -= bt.ask(k.y2) - bt.ask(k.y1 - 1);
            } else if (k.type == 0) {
                bt.upd(k.y1, 1);
            } else {
                res[k.idx] += bt.ask(k.y2) - bt.ask(k.y1 - 1);
            }
        }
    }
};

vector<int> check_validity(int N, vector<int> X, vector<int> Y, 
                           vector<int> S, vector<int> E, 
                           vector<int> L, vector<int> R) {

    int M = X.size(), Q = S.size();
    /* create a rooted tree, such that any node u can reach its subtrees for L and R */
    disj dsL(N), dsR(N);
    graph lowerL(N), upperR(N);
    vector<vector<int>> pending_edgeL(N), pending_edgeR(N);
    vector<vector<int>> binary_liftL(N, vector<int>(20, -1)), binary_liftR(N, vector<int>(20, -1));
    for (int i = 0; i < M; i++) {
        if (X[i] > Y[i]) swap(X[i], Y[i]);
        pending_edgeL[X[i]].emplace_back(Y[i]);
        pending_edgeR[Y[i]].emplace_back(X[i]);
    }
    /* build tree for L, iterating high vertices first (most limited if L is high) */
    for (int i = N - 1; i >= 0; i--) {
        for (auto &j : pending_edgeL[i]) {
            int p = dsL.par(j);
            if (i == p) continue;
            dsL.p[p] = i;
            binary_liftL[p][0] = i;
            lowerL.add_edge(i, p);
        }
    }
    /* do the same for tree R */
    for (int i = 0; i < N; i++) {
        for (auto &j : pending_edgeR[i]) {
            int p = dsR.par(j);
            if (i == p) continue;
            dsR.p[p] = i;
            binary_liftR[p][0] = i;
            upperR.add_edge(i, p);
        }
    }
    // cout << "GOT HERE" << endl;
    /* create binary lifting for each query S and E, find minimum from S and maximum from E (vertex number) */
    for (int j = 1; j < 20; j++) {
        for (int i = 0; i < N; i++) {
            if (binary_liftL[i][j - 1] != -1) binary_liftL[i][j] = binary_liftL[binary_liftL[i][j - 1]][j - 1];
            if (binary_liftR[i][j - 1] != -1) binary_liftR[i][j] = binary_liftR[binary_liftR[i][j - 1]][j - 1];
        }
    }
    // cout << "GOT HERE" << endl;
    /* create euler tour -> represent the graph with intervals */
    vector<pair<int, int>> intervalL(N), intervalR(N);
    vector<int> eulerL, eulerR;
    lowerL.dfs(0, -1, intervalL, eulerL);
    upperR.dfs(N - 1, -1, intervalR, eulerR);
    /* get index of intervalR */
    vector<int> other_name(N);
    for (int i = 0; i < N; i++) {
        other_name[eulerL[i]] = i; //map eulerL to 0...(N - 1)
    }
    // cout << "GOT HERE" << endl;
    /* fenwick tree + line sweep technique to solve, decompose if (intervalL[i] == intervalR[j]) add point (i, j), then check for rectangle for each query */
    solver Solver(N);
    for (int i = 0; i < N; i++) {
        Solver.add_point(i, other_name[eulerR[i]]); //apply the same mapping to eulerR
    }
    // cout << "GOT HERE" << endl;
    for (int i = 0; i < Q; i++) { //get updates, lift S and E with binary lifting
        int s = S[i], e = E[i];
        for (int j = 20; j >= 0; j--) { //binary lifting
            if (binary_liftL[s][j] != -1 && L[i] <= binary_liftL[s][j]) s = binary_liftL[s][j];
            if (binary_liftL[e][j] != -1 && binary_liftL[e][j] <= R[i]) e = binary_liftL[e][j];
        }
        Solver.add_query(intervalL[s].first, intervalL[s].second, intervalR[i].first, intervalR[i].second, i);
    }
    // cout << "GOT HERE" << endl;
    vector<int> res(Q);
    Solver.line_sweep(res);
    for (int i = 0; i < Q; i++) {
        res[i] = (res[i] > 0);
    }
    return res;
}

/*

6 6 3
5 1
1 2
1 3
3 4
3 0
5 2
4 2 1 2
4 2 2 2
5 4 3 4

*/

Compilation message (stderr)

werewolf.cpp: In member function 'void solver::bit::upd(int, int)':
werewolf.cpp:52:35: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
             for (int i = n + 1; i < tree.size(); i += i & -i) {
                                 ~~^~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...