Submission #235483

#TimeUsernameProblemLanguageResultExecution timeMemory
235483lyc늑대인간 (IOI18_werewolf)C++14
15 / 100
543 ms228960 KiB
#include "werewolf.h"
#include <bits/stdc++.h>
using namespace std;

#define TRACE(x) cout << #x << " :: " << x << endl;
#define _ << " " <<
#define FOR(i,a,b) for (int i=(a);i<=(b);++i)
#define RFOR(i,a,b) for (int i=(a);i>=(b);--i)
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(), (x).end()

const int mxN = 2e5+5;
const int lgN = 17;
const int mxM = 4e5+5;
const int mxQ = 2e5+5;

int N, M, Q;
struct Edge { int X, Y, W; } edge[mxM];
struct Query { int S, E, L, R, id; } query[mxQ];

struct SegmentTree {
    multiset<int> d[4*mxN];
    int n;

    SegmentTree(int n): n(n) {}
    void update(int x, int u, int v, int s, int e, int p) {
        auto it = d[p].find(u);
        if (it != d[p].end()) d[p].erase(it);
        d[p].insert(v);
        if (s != e) {
            int m = (s+e)/2;
            if (x <= m) update(x,u,v,s,m,p*2);
            else update(x,u,v,m+1,e,p*2+1);
        }
    }
    inline void update(int x, int u, int v) { update(x,u,v,0,n-1,1); }
    bool query(int x, int y, int v, int s, int e, int p) {
        if (s == x && e == y) {
            return d[p].lower_bound(v) != d[p].upper_bound(v);
        } else {
            int m = (s+e)/2;
            if (y <= m) return query(x,y,v,s,m,p*2);
            if (x >  m) return query(x,y,v,m+1,e,p*2+1);
            return query(x,m,v,s,m,p*2) || query(m+1,y,v,m+1,e,p*2+1);
        }
    }
    inline bool query(int x, int y, int v) { return query(x,y,v,0,n-1,1); }
} *ST;

struct KruskalTree {
    static const int mxV = 2*mxN;
    int pa[mxV], v[mxV];
    vector<int> al[mxV];
    int cnt, fa[mxV][lgN+1], pre[mxV], pst[mxV], dfsT;

    KruskalTree(int n) {
        FOR(i,0,n-1){
            pa[i] = i;
            v[i] = -1;
        }
        cnt = n;
        memset(fa,-1,sizeof fa);
    }
    int finds(int i) { return (pa[i] == i) ? i : (pa[i] = finds(pa[i])); }
    bool unions(int i, int j, int w) {
        int x = finds(i), y = finds(j);
        if (x != y) {
            pa[cnt] = cnt;
            v[cnt] = w;
            al[cnt].push_back(x);
            al[cnt].push_back(y);
            fa[x][0] = cnt;
            fa[y][0] = cnt;
            pa[x] = pa[y] = cnt;
            ++cnt;
            return true;
        } return false;
    }
    void dfs(int u) {
        pre[u] = dfsT++;
        FOR(k,1,lgN){
            if (fa[u][k-1] == -1) fa[u][k] = -1;
            else fa[u][k] = fa[fa[u][k-1]][k-1];
        }
        for (int v : al[u]) { dfs(v); }
        pst[u] = dfsT-1;
        //TRACE(u _ v[u] _ pre[u] _ pst[u]);
    }
    void init() {
        dfsT = 0;
        dfs(cnt-1);
    }
    int findFaGE(int u, int val) {
        RFOR(k,lgN,0){
            if (fa[u][k] != -1 && v[fa[u][k]] >= val) u = fa[u][k];
        }
        return u;
    }
} *KT;

struct UnionFind {
    int pa[mxN];
    set<int> child[mxN];
    UnionFind(int n) {
        FOR(i,0,n-1){
            pa[i] = i;
            child[i].insert(i);
            ST->update(KT->pre[i],-1,i);
        }
    }
    int finds(int i) { return (pa[i] == i) ? i : (pa[i] = finds(pa[i])); }
    bool unions(int i, int j) {
        int x = finds(i), y = finds(j);
        if (x != y) {
            if (SZ(child[x]) < SZ(child[y])) swap(x,y);
            for (auto& u : child[y]) {
                assert(pa[u] == y);
                pa[u] = x;
                ST->update(KT->pre[u],y,x);
                child[x].insert(u);
            }
            child[y].clear();
            return true;
        } return false;
    }
} *UF;

std::vector<int> check_validity(int _N, std::vector<int> X, std::vector<int> Y,
                                std::vector<int> S, std::vector<int> E,
                                std::vector<int> L, std::vector<int> R) {
    N = _N, M = SZ(X), Q = SZ(S);
    FOR(i,0,M-1){
        edge[i] = (Edge){ X[i], Y[i], min(X[i],Y[i]) };
    }
    FOR(i,0,Q-1){
        query[i] = (Query){ S[i], E[i], L[i], R[i], i };
    }

    sort(edge,edge+M,[](Edge a, Edge b){
            if (a.W == b.W) return (a.X == b.X ? a.Y < b.Y : a.X < b.X);
            return a.W > b.W;
            });
    sort(query,query+Q,[](Query a, Query b){
            if (a.R == b.R) return a.id < b.id;
            return a.R < b.R;
            });

    KT = new KruskalTree(N);
    FOR(i,0,M-1){
        KT->unions(edge[i].X,edge[i].Y,edge[i].W);
    }
    KT->init();

    FOR(i,0,M-1) edge[i].W = max(edge[i].X,edge[i].Y);
    sort(edge,edge+M,[](Edge a, Edge b){
            if (a.W == b.W) return (a.X == b.X ? a.Y < b.Y : a.X < b.X);
            return a.W < b.W;
            });
    ST = new SegmentTree(2*N);
    UF = new UnionFind(N);
    vector<int> ans(Q);
    int ei = 0;
    FOR(i,0,Q-1){
        while (ei < M && edge[ei].W <= query[i].R) {
            UF->unions(edge[ei].X,edge[ei].Y);
            ++ei;
        }
        int ep = UF->finds(query[i].E);
        int sp = KT->findFaGE(query[i].S,query[i].L);
        //TRACE(ep _ sp);
        ans[query[i].id] = ST->query(KT->pre[sp],KT->pst[sp],ep);
    }
    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...