Submission #684114

# Submission time Handle Problem Language Result Execution time Memory
684114 2023-01-20T12:31:39 Z 79brue Simurgh (IOI17_simurgh) C++17
0 / 100
1 ms 596 KB
#include "simurgh.h"
#include <bits/stdc++.h>

using namespace std;

struct unionFind{
    int par[502];

    void init(int n){
        for(int i=0; i<n; i++) par[i] = i;
    }

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

    void merge(int x, int y){
        x = find(x), y = find(y);
        par[y] = x;
    }
};

struct Edge{
    int s, e, idx;
    Edge(){}
    Edge(int s, int e, int idx): s(s), e(e), idx(idx){}
};

struct Comparison{
    int a, b, v; /// ans[a] - ans[b] = v
    Comparison(){}
    Comparison(int a, int b, int v): a(a), b(b), v(v){}

    bool operator<(const Comparison &r)const{
        return abs(v) > abs(r.v);
    }
};

int n, m;
vector<Edge> link[502];
int edgeIdx[502][502];
int ex[150002], ey[150002];
bool ans[150002];

void oneTree();
void everyEdge();

vector<int> find_roads(int N, vector<int> u, std::vector<int> v) {
    n = N, m = (int)u.size();
    for(int i=0; i<n; i++) for(int j=0; j<n; j++) edgeIdx[i][j] = -1;
    for(int i=0; i<m; i++){
        link[u[i]].push_back(Edge(u[i], v[i], i));
        link[v[i]].push_back(Edge(v[i], u[i], i));
        ex[i] = u[i], ey[i] = v[i];
        edgeIdx[ex[i]][ey[i]] = i;
        edgeIdx[ey[i]][ex[i]] = i;
    }

    oneTree();
    everyEdge();

    vector<int> ret;
    for(int i=0; i<m; i++) if(ans[i]) ret.push_back(i);
    return ret;
}

vector<Edge> treeLink[502];
vector<int> treeEdges;
bool inTree[150002];
int depth[502], par[502], LCADB[502][10];

bool checked[150002];

void dfs_tree(int x, int p){
    par[x] = p;
    for(Edge y: treeLink[x]){
        if(y.e == p) continue;
        depth[y.e] = depth[x] + 1;
        dfs_tree(y.e, x);
    }
}

int getLCA(int x, int y){
    if(depth[x] > depth[y]) swap(x, y);
    for(int d=9; d>=0; d--) if((depth[y] - depth[x]) & (1<<d)) y = LCADB[y][d];
    if(x==y) return x;
    for(int d=9; d>=0; d--) if(LCADB[x][d] != LCADB[y][d]) x = LCADB[x][d], y = LCADB[y][d];
    return par[x];
}

void apply(int x, int t){
    if(checked[x] && ans[x] != t) exit(1);
    checked[x] = 1, ans[x] = t;
}

void oneTree(){
    /// 아무 트리나 만들기
    unionFind dsu;
    dsu.init(n);
    for(int i=0; i<m; i++){
        if(dsu.find(ex[i]) != dsu.find(ey[i])){
            dsu.merge(ex[i], ey[i]);
            inTree[i] = 1;
            treeLink[ex[i]].push_back(Edge(ex[i], ey[i], i));
            treeLink[ey[i]].push_back(Edge(ey[i], ex[i], i));
            treeEdges.push_back(i);
        }
    }

    int treeSum = count_common_roads(treeEdges);

    /// 트리를 탐색하기
    dfs_tree(0, -1);
    for(int i=0; i<n; i++) LCADB[i][0] = par[i];
    for(int d=1; d<10; d++) for(int i=0; i<n; i++) LCADB[i][d] = (LCADB[i][d-1] == -1 ? -1 : LCADB[LCADB[i][d-1]][d-1]);

    /// 각 간선이 포함되는지 확인하기
    vector<Comparison> compare;

    for(int edge: treeEdges){
        int u = ex[edge], v = ey[edge];
        if(depth[u] > depth[v]) swap(u, v);

        /// 위로 가는 간선이 있는지 보자
        int up = -1;
        for(int i=0; i<m; i++){
            if(inTree[i]) continue;
            if((getLCA(v, ex[i]) == v) == (getLCA(v, ey[i]) == v)) continue;
            up = i;
            break;
        }
        if(up == -1){
            checked[edge] = 1;
            ans[edge] = 1;
            continue;
        }

        /// 쿼리를 날려 확인해 보자
        vector<int> qv1 = treeEdges;
        qv1.erase(find(qv1.begin(), qv1.end(), edge));
        qv1.push_back(up);
        int qa1 = count_common_roads(qv1);
        compare.push_back(Comparison(edge, up, treeSum - qa1));

        /// 이제 쿼리를 하나 더 날리자
        int top = getLCA(ex[up], ey[up]);
        int highest;
        if(top == ex[up]) highest = edgeIdx[ey[up]][par[ey[up]]];
        else if(top == ey[up]) highest = edgeIdx[ex[up]][par[ex[up]]];
        else if(v != ex[up]) highest = edgeIdx[ex[up]][par[ex[up]]];
        else if(v != ey[up]) highest = edgeIdx[ey[up]][par[ey[up]]];
        else exit(1);

        vector<int> qv2 = qv1;
        qv2.erase(find(qv2.begin(), qv2.end(), highest));
        qv2.push_back(edge);
        int qa2 = count_common_roads(qv2);
        compare.push_back(Comparison(highest, edge, qa1 - qa2));
    }

    /// 비교 데이터를 바탕으로 결정하자.
    sort(compare.begin(), compare.end());
    for(Comparison com: compare){
        if(com.v){
            if(com.v == 1) apply(com.a, 1), apply(com.b, 0);
            else           apply(com.b, 1), apply(com.a, 0);
        }
        else if(checked[com.a] || checked[com.b]){
            assert(!checked[com.a] || !checked[com.b] || ans[com.a] == ans[com.b]);
            int result = ans[com.a] || ans[com.b];
            apply(com.a, result), apply(com.b, result);
        }
    }

    for(int edge: treeEdges){
        assert(checked[edge]);
    }
}

void dnc(vector<int> &edgeList){
    if(edgeList.empty()) return;

    vector<int> qv;
    unionFind dsu;
    dsu.init(n);
    for(auto x: edgeList){
        qv.push_back(x);
        dsu.merge(ex[x], ey[x]);
    }
    int base = 0;
    for(auto x: treeEdges){
        if(dsu.find(ex[x]) == dsu.find(ey[x])) continue;
        base += ans[x];
        qv.push_back(x);
        dsu.merge(ex[x], ey[x]);
    }
    int value = count_common_roads(qv) - base;
    if(!value) return;
    if((int)edgeList.size() == 1){
        apply(edgeList[0], 1);
        return;
    }

    vector<int> list1, list2;
    int m = (int)edgeList.size() / 2;
    for(int i=0; i<(int)edgeList.size(); i++){
        if(i < m) list1.push_back(edgeList[i]);
        else list2.push_back(edgeList[i]);
    }

    dnc(list1);
    dnc(list2);
}

void everyEdge(){
    for(int i=0; i<n; i++){
        /// 정점 i 주변의 간선들을 찾을 것이다.
        vector<int> searchTo;
        for(Edge e: link[i]) if(!inTree[e.idx]) searchTo.push_back(e.idx);
        dnc(searchTo);
    }
}
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 596 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 596 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 596 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Correct 1 ms 340 KB correct
2 Runtime error 1 ms 596 KB Execution killed with signal 11
3 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 596 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -