Submission #932926

#TimeUsernameProblemLanguageResultExecution timeMemory
932926asdasdqwerLove Polygon (BOI18_polygon)C++14
100 / 100
289 ms27732 KiB
#include <bits/stdc++.h>
using namespace std;

#define int int64_t

signed main() {
    int n;cin>>n;
    
    if (n % 2 != 0) {
        cout<<-1<<"\n";
        return 0;
    }

    map<string,int> mp;
    vector<vector<int>> in(n);
    vector<int> out(n);
    int cnt=0;
    for (int i=0;i<n;i++) {
        string s1, s2;cin>>s1>>s2;
        if (mp.find(s1) == mp.end()) {
            mp[s1] = cnt++;
        }

        if (mp.find(s2) == mp.end()) {
            mp[s2] = cnt++;
        }
        if (mp[s1] != mp[s2])
            in[mp[s2]].push_back(mp[s1]);
        out[mp[s1]] = mp[s2];
    }

    // remove all relationships (cycles of length 2)
    int swaps = n;
    vector<bool> vis1(n, false);

    for (int i=0;i<n;i++) {
        if (vis1[i])continue;
        if (out[out[i]] != i || out[i] == i) continue;
        vis1[i] = true;
        vis1[out[i]] = true;
        for (auto &x:in[i]) {
            out[x] = x;
        }

        for (auto &x:in[out[i]]) {
            out[x] = x;
        }

        swaps -= 2;
    }

    // get rid of all cycles of length 1 (people that love themselves), and the respective lines connected to them
    vector<int> dpWith(n, 0), dpWithout(n, 0);
    function<void(int)> dfs1=[&](int node) {
        vis1[node] = true;
        int sm = 0;
        for (auto &x:in[node]) {
            dfs1(x);
            dpWithout[node] += max(dpWith[x], dpWithout[x]);
            sm += max(dpWith[x], dpWithout[x]);
        }

        for (auto &x:in[node]) {
            dpWith[node] = max(dpWith[node], sm - max(dpWith[x], dpWithout[x]) + dpWithout[x] + 1);
        }
    };

    for (int i=0;i<n;i++) {
        if (out[i] == i && !vis1[i]) {
            dfs1(i);
            swaps -= max(dpWith[i], dpWithout[i]);
        }
    }

    // find all nodes that are part of a cycle
    vector<bool> incycle(n, false);
    vector<int> stat(n, 0);
    vector<bool> vis = vis1;

    function<int(int)> dfs2=[&](int node) -> int {
        vis[node] = true;
        // still being processed
        stat[node] = 1;
        if (stat[out[node]] == 0) {
            int d = dfs2(out[node]);
            if (d != -1) {
                incycle[node] = true;
            }

            if (d == node) {
                d = -1;
            }
            stat[node] = 2;
            return d;
        }

        else if (stat[out[node]] == 1) {
            stat[node] = 2;
            incycle[node] = true;
            return out[node];
        }

        // finished processing
        stat[node] = 2;
        return -1;
    };

    for (int i=0;i<n;i++) {
        if (!vis[i]) dfs2(i);
    }

    // calculate dp values for all nodes in a cycle
    function<void(int)> dfs3=[&](int node) {
        int sm = 0;
        for (auto &x:in[node]) {
            if (incycle[x])continue;
            dfs3(x);
            dpWithout[node] += max(dpWith[x], dpWithout[x]);
            sm += max(dpWith[x], dpWithout[x]);
        }

        for (auto &x:in[node]) {
            if (incycle[x])continue;
            dpWith[node] = max(dpWith[node], sm - max(dpWith[x], dpWithout[x]) + dpWithout[x] + 1);
        }
    };

    for (int i=0;i<n;i++) {
        if (incycle[i]) {
            dfs3(i);
            swaps -= dpWith[i];
        }
    }

    vis.clear();
    vis.assign(n, false);

    for (int i=0;i<n;i++) {
        if (incycle[i] && !vis[i]) {
            int pt = i;
            vector<bool> pos;
            do {
                pos.push_back(dpWith[pt] == dpWithout[pt]);
                vis[pt] = true;
                pt = out[pt];
            } while (pt != i);
            
            vector<bool> tmp;
            while (pos.size() && pos.back() == true) {
                tmp.push_back(true);
                pos.pop_back();
            }

            for (bool x:pos) {
                tmp.push_back(x);
            }
            tmp.push_back(false);

            stack<bool> st;
            for (bool x:tmp) {
                if (x) {
                    st.push(x);
                }

                else {
                    swaps -= ((int)st.size() / 2);
                    while (st.size()) st.pop();
                }
            }
        }
    }

    cout<<swaps<<"\n";
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...