제출 #829378

#제출 시각아이디문제언어결과실행 시간메모리
829378Josia늑대인간 (IOI18_werewolf)C++17
100 / 100
1467 ms150936 KiB
#include "werewolf.h"
#include <bits/stdc++.h>

using namespace std;


int N, M, Q;
vector<vector<int>> graph;
vector<int> human, wolf;
vector<vector<int>> treeWolf;
vector<vector<int>> treeHuman;
vector<pair<int, int>> prepostWolf;
vector<pair<int, int>> prepostHuman;
vector<vector<int>> jumpWolf;
vector<vector<int>> jumpHuman;


struct ufToMakeArrays {
    vector<int> chefs;
    void init() {
        chefs.resize(N);
        for (int i = 0; i<N; i++) {
            chefs[i] = i;
        }
    }

    int find(int x) {
        if (chefs[x] == x) return x;
        return chefs[x] = find(chefs[x]);
    }

    void unite(int a, int b, bool minmax) {
        a = find(a);
        b = find(b);
        if (a == b) return;
        if (minmax?a<b:a>b) swap(a, b);

        chefs[b] = a;
    }


    void makeTreeWolf() {
        init();
        for (int i = 0; i<N; i++) {
            for (int u: graph[i]) {
                if (u >= i) continue;
                if (find(u) == find(i)) continue;
                treeWolf[find(i)].push_back(find(u));
                treeWolf[find(u)].push_back(find(i));
                unite(u, i, 1);
            }
        }
    }


    void makeTreeHuman() {
        init();
        for (int i = N-1; i>=0; i--) {
            for (int u: graph[i]) {
                if (u <= i) continue;
                if (find(u) == find(i)) continue;
                treeHuman[find(i)].push_back(find(u));
                treeHuman[find(u)].push_back(find(i));
                unite(u, i, 0);
            }
        }
    }

    void dfsWolf(int v, int p) {
        jumpWolf[0][v] = p;
        prepostWolf[v].first = wolf.size();
        wolf.push_back(v);
        for (int i: treeWolf[v]) {
            if (i == p) continue;
            dfsWolf(i, v);
        }
        prepostWolf[v].second = wolf.size()-1;
    }

    void dfsHuman(int v, int p) {
        jumpHuman[0][v] = p;
        prepostHuman[v].first = human.size();
        human.push_back(v);
        for (int i: treeHuman[v]) {
            if (i == p) continue;
            dfsHuman(i, v);
        }
        prepostHuman[v].second = human.size()-1;
    }


    void make() {
        treeHuman.assign(N, vector<int>()); treeWolf.assign(N, vector<int>());

        makeTreeWolf(); makeTreeHuman();

        wolf.clear(); human.clear();

        prepostHuman.assign(N, {0, 0});
        prepostWolf.assign(N, {0, 0});

        jumpHuman.assign(20, vector<int>(N));
        jumpWolf.assign(20, vector<int>(N));

        dfsWolf(N-1, -1); dfsHuman(0, -1);


        for (int i = 1; i<20; i++) {
            for (int j = 0; j<N; j++) {
                jumpHuman[i][j] = jumpHuman[i-1][j] == -1 ? -1 : jumpHuman[i-1][jumpHuman[i-1][j]];
                jumpWolf[i][j] = jumpWolf[i-1][j] == -1 ? -1 : jumpWolf[i-1][jumpWolf[i-1][j]];
            }
        }
    }
};



vector<int> wolfInv, humanInv, humanToWolf;

void makeInv() {
    wolfInv.resize(N);
    humanInv.resize(N);
    for (int i = 0; i<N; i++) wolfInv[wolf[i]] = i;
    for (int i = 0; i<N; i++) humanInv[human[i]] = i;

    humanToWolf.resize(N);
    for (int i = 0; i<N; i++) humanToWolf[i] = wolfInv[human[i]];
}


struct seg {
    struct node {
        int val=0, left=-1, right=-1;
    };

    vector<node> tree = {node()};

    void build(int v, int rl, int rr) {
        if (rl == rr) return;

        tree[v].left = tree.size();
        tree.push_back(node());
        tree[v].right = tree.size();
        tree.push_back(node());

        int rm = (rl + rr)/2;

        build(tree[v].left, rl, rm);
        build(tree[v].right, rm+1, rr);
    }

    int update(int v, int rl, int rr, int pos, int x) {
        if (rl == rr) {
            int newV = tree.size();
            tree.push_back(tree[v]);

            tree[newV].val += x;
            return newV;
        }
        int rm = (rl + rr)/2;

        int newV = tree.size();
        tree.push_back(tree[v]);

        if (pos <= rm) tree[newV].left = update(tree[newV].left, rl, rm, pos, x);
        else tree[newV].right = update(tree[newV].right, rm+1, rr, pos, x);

        tree[newV].val = tree[tree[newV].left].val + tree[tree[newV].right].val;

        return newV;
    }

    int query(int v, int rl, int rr, int ql, int qr) {
        if (ql > qr) return 0;
        if (rl == ql && rr == qr) return tree[v].val;

        int rm = (rl + rr)/2;

        return query(tree[v].left, rl, rm, ql, min(qr, rm)) + query(tree[v].right, rm+1, rr, max(ql, rm+1), qr);
    }

    vector<int> times;

    int queryDouble(int hl, int hr, int wl, int wr) {
        // cerr << query(times[wr], 0, N-1, hl, hr) << " - " << query(times[wl-1], 0, N-1, hl, hr) << "\n";
        // return query(times[wr], 0, N-1, hl, hr) - (wl==0?0:query(times[wl-1], 0, N-1, hl, hr));
        return query(times[hr], 0, N-1, wl, wr) - (hl==0?0:query(times[hl-1], 0, N-1, wl, wr));
    }

    void init() {
        build(0, 0, N-1);
        for (int i = 0; i<N; i++) {
            times.push_back(update(i==0?0:times.back(), 0, N-1, humanToWolf[i], 1));
        }
        assert((int)times.size() == N);
    }
};


pair<int, int> getRangeHuman(int pos, int lim) {
    for (int i = 19; i>=0; i--) {
        if (jumpHuman[i][pos] != -1 && jumpHuman[i][pos] >= lim) {
            pos = jumpHuman[i][pos];
        }
    }
    return prepostHuman[pos];
}

pair<int, int> getRangeWolf(int pos, int lim) {
    for (int i = 19; i>=0; i--) {
        if (jumpWolf[i][pos] != -1 && jumpWolf[i][pos] <= lim) {
            pos = jumpWolf[i][pos];
        }
    }
    return prepostWolf[pos];
}


vector<int> check_validity(int _N, vector<int> X, vector<int> Y, vector<int> S, vector<int> E, vector<int> L, vector<int> R) {
    N = _N;
    M = X.size();
    Q = S.size();

    graph.clear();
    graph.resize(N);
    for (int i = 0; i<M; i++) {
        graph[X[i]].push_back(Y[i]);
        graph[Y[i]].push_back(X[i]);
    }

    ufToMakeArrays blub;
    blub.make();

    makeInv();


    // for (int i: human) cerr << i << " ";
    // cerr << "\n";
    // for (int i: wolf) cerr << i << " ";
    // cerr << "\n";


    seg tree;

    tree.init();



    vector<int> res(Q, 0);

    for (int i = 0; i<Q; i++) {
        // cerr << humanInv[S[i]] << "\n";
        pair<int, int> rangeHuman = getRangeHuman(S[i], L[i]);
        pair<int, int> rangeWolf = getRangeWolf(E[i], R[i]);

        // cerr << rangeHuman.first << " " << rangeHuman.second << " " << rangeWolf.first << " " << rangeWolf.second << "\n";

        // cerr << tree.queryDouble(rangeHuman.first, rangeHuman.second, rangeWolf.first, rangeWolf.second) << "\n";

        if (tree.queryDouble(rangeHuman.first, rangeHuman.second, rangeWolf.first, rangeWolf.second)) res[i] = 1;
    }
    return res;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...