QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#380707#8055. BalancepopeML 1ms5708kbC++208.3kb2024-04-07 09:04:092024-04-07 09:04:11

Judging History

你现在查看的是最新测评结果

  • [2024-04-07 09:04:11]
  • 评测
  • 测评结果:ML
  • 用时:1ms
  • 内存:5708kb
  • [2024-04-07 09:04:09]
  • 提交

answer

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = a; i < (b); i++)
#define all(x) begin(x),end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

#define trav(a, x) for (auto& a: x)
#define f first
#define s second
#define pb push_back
const char nl = '\n';

#ifdef DBG
void dbg_out() { cerr << nl; }
template <typename Head, typename... Tail>
void dbg_out(Head H, Tail... T) {
    cerr << ' ' << H;
    dbg_out(T...);
}
#define dbg(...) dbg_out(__VA_ARGS__)
#else
#define dbg(...)
#endif

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

const int MX = 1e5+5;
int par[MX];
int SZ[MX];

int find(int x) {
    return (x==par[x]?x:par[x]=find(par[x]));
}
void merge(int a, int b) {
    a = find(a), b = find(b);
    if (a == b) return;
    if (SZ[a] < SZ[b]) swap(a, b);
    SZ[a] += SZ[b];
    par[b] = a;
    SZ[b] = 0;
}
vi gr[MX];
vector<pii> edges;

vi num, st;
vector<vector<pii>> ed;
int Time;
vector<pii> bridge_edges;
template <class F>
int dfs(int at, int par, F& f) {
    int me = num[at] = ++Time, e, y, top=me;
    for (auto pa : ed[at]) if (pa.second != par) {
        tie(y, e) = pa;
        if (num[y]) {
            top = min(top, num[y]);
            if (num[y] < me) {
                st.pb(e);
            }
        } else {
            int si = sz(st);
            int up = dfs(y, e, f);
            top = min(top, up);
            if (up == me) {
                st.pb(e);
                f(vi(st.begin()+si, st.end()));
                st.resize(si);
            }
            else if (up < me) st.pb(e);
            else {
                // e is a bridge
                // create an edge in the graph
                bridge_edges.pb({edges[e].f, edges[e].s});
            }
        }
    }
    return top;
}
template <class F>
void bicomps(F f) {
    num.assign(sz(ed), 0);
    rep(i, 0, sz(ed)) if (!num[i]) dfs(i, -1, f);
}

struct Info {
    int subtreeSize = 0;
    int downLen = 0;
    int downCh = -1;
    int upLen = 0;
    int upCh = -1;
};

Info infos[MX];
bool good[MX];
int n, m;

int best = 0;
int root, upNode, downNode;

void solve(int v, int p) {
    infos[v].subtreeSize = SZ[find(v)];
    vector<pii> ups;
    vector<pii> downs;
    trav(u, gr[v]) {
        int node = find(u);
        if (node == p) continue;
        solve(node, v);
        // check if this is a good break edge going either up or down
        int valUp = infos[node].upLen;
        int valDown = infos[node].downLen;
        if (good[infos[node].subtreeSize]) {
            // then we can add to 1 this
            valUp++;
        }
        if (good[n-infos[node].subtreeSize]) {
            valDown++;
        }
        ups.pb({valUp, node});
        downs.pb({valDown, node});
        infos[v].subtreeSize += infos[node].subtreeSize;
    }
    if (sz(ups) == 0) return;
    // find highest two
    sort(all(ups));
    reverse(all(ups));
    sort(all(downs));
    reverse(all(downs));
    // first just set the vals of v
    infos[v].upLen = ups[0].f;
    infos[v].upCh = ups[0].s;
    infos[v].downLen = downs[0].f;
    infos[v].downCh = downs[0].s;
    dbg("for node v", v);
    dbg("subtreeSize", infos[v].subtreeSize);
    dbg("upLen and upCh", infos[v].upLen, infos[v].upCh);
    dbg("downLen and downCh", infos[v].downLen, infos[v].downCh);
    {
        int len = ups[0].f;
        if (len > best) {
            best = len;
            root = v;
            upNode = ups[0].s;
            downNode = -1;
        }

        len = downs[0].f;
        if (len > best) {
            best = len;
            root = v;
            upNode = -1;
            downNode = downs[0].s;
        }
    }
    if (sz(ups) == 1) return;
    // merge the best up and best down as long as they're not the same child
    // try best up and best down
    // also just try best up and nothing and best down and nothing
    
    if (ups[0].s != downs[0].s) {
        int len = ups[0].f + downs[0].f;
        if (len > best) {
            best = len;
            root = v;
            upNode = ups[0].s;
            downNode = downs[0].s;
        }
    }
    if (ups[0].s != downs[1].s) {
        int len = ups[0].f + downs[1].f;
        if (len > best) {
            best = len;
            root = v;
            upNode = ups[0].s;
            downNode = downs[1].s;
        }
    }
    if (ups[1].s != downs[0].s) {
        int len = ups[1].f + downs[0].f;
        if (len > best) {
            best = len;
            root = v;
            upNode = ups[1].s;
            downNode = downs[0].s;
        }
    }
    
}

int vis[MX];
void mark(int v, int x, int nxt) {
    if (v == nxt) return; // don't cross into next section
    if (vis[v]) return;
    vis[v] = x;
    trav(u, gr[v]) {
        mark(u, x, nxt);
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(0);
    cin.exceptions(cin.failbit);
    int t; cin >> t;
    while (t--) {
        bridge_edges.clear();
        bridge_edges.shrink_to_fit();
        best = -1;
        root = upNode = downNode = -1;
        cin >> n >> m;
        // reset everything
        rep(i, 0, n) {
            par[i] = i;
            SZ[i] = 1;
        }
        rep(i, 0, n) {
            infos[i] = Info();
        }
        rep(i, 0, n) vis[i] = 0;
        rep(i, 0, n) {
            gr[i].clear();
            gr[i].shrink_to_fit();
        }
        edges.clear();
        edges.shrink_to_fit();
        int eid = 0; 
        ed.clear();
        ed.shrink_to_fit();
        ed.resize(n);
        Time = 0;
        num.clear();
        num.shrink_to_fit();
        st.clear();
        st.shrink_to_fit();
        rep(i, 0, m) {
            int u, v; cin >> u >> v;
            u--; v--;
            edges.pb({u, v});
            ed[u].emplace_back(v, eid);
            ed[v].emplace_back(u, eid++);
        }
        bicomps([&](const vi& edgelist) {
            // merge the whole component togther
            trav(e, edgelist) {
                merge(edges[e].f, edges[e].s);
            }
        });
        // actually add the bridge edges now
        trav(p, bridge_edges) {
            dbg("bridge", find(p.f), find(p.s));
            gr[find(p.f)].pb(find(p.s));
            gr[find(p.s)].pb(find(p.f));
        }
        int freq[n+1]; rep(i, 0, n+1) freq[i] = 0;
        rep(i, 0, n) {
            int x; cin >> x;
            freq[x]++;
        }
        vector<pii> sizes;
        rep(i, 1, n+1) {
            if (freq[i]) sizes.pb({i, freq[i]});
        }
        // find all the good breaks
        rep(i, 0, n) good[i] = 0;
        int cur = 0;
        trav(p, sizes) {
            dbg(p.f, p.s);
            cur += p.s;
            if (cur != n) good[cur] = 1;
        }
        assert(cur == n);

        // now dfs from random root
        solve(find(0), -1);
        int d = sz(sizes);
        dbg("best len", best);
        dbg("root, upNode, downNode", root, upNode, downNode);
        if (best != d-1) {
            cout << "No" << nl;
            continue;
        }
        cout << "Yes" << nl;
        // we have a path with d-1 breaks in it
        // this path is stored in root, upNode, downNode
        vi path;
        while (upNode != -1) {
            path.pb(upNode);
            upNode = infos[upNode].upCh;
        }
        reverse(all(path));
        path.pb(root);
        while (downNode != -1) {
            path.pb(downNode);
            downNode = infos[downNode].downCh;
        }

        // trav(v, path) cerr << v << ' '; cerr << nl;
        bool beforeRoot = 1;
        rep(i, 0, sz(path)) {
            if (path[i] == root) beforeRoot = 0;
            if (beforeRoot && !good[infos[path[i]].subtreeSize]) continue;
            else if (!beforeRoot) {
                if (i != sz(path)-1 && !good[n-infos[path[i+1]].subtreeSize]) {
                    continue;
                }
            }
            int nxt = -1;
            // check if this is actually a good break
            if (i != sz(path)-1) nxt = path[i+1];
            mark(path[i], sizes[i].f, nxt);
        }
        rep(i, 0, n) {
            cout << vis[find(i)] << " ";
        }
        cout << nl;
    }

}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 5708kb

input:

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

output:

Yes
5 4 3 2 1 
No
Yes
2 2 2 3 1 
Yes
2 2 1 1 1 
No

result:

ok ok (5 test cases)

Test #2:

score: -100
Memory Limit Exceeded

input:

100000
4 3
4 2
1 3
2 1
2 1 3 2
5 7
2 5
5 3
2 3
5 1
4 3
2 4
4 3
1 3 1 1 2
3 2
2 1
2 3
1 1 1
4 7
3 4
1 4
2 3
4 3
4 2
3 1
4 3
2 3 3 2
4 6
2 4
3 1
1 2
1 2
2 3
4 2
1 1 3 3
4 7
3 2
4 2
1 2
3 4
3 2
2 4
3 4
2 1 1 1
5 5
3 2
1 5
4 5
4 3
2 1
1 2 2 3 2
3 5
2 3
1 3
3 1
3 1
2 1
3 2 3
2 3
2 1
2 1
1 2
1 1
2 3
2 1
1...

output:


result: