队伍中排有 n 名玩家,等待体验该游戏。玩家按排队顺序编号为 0 到 n−1。编号 0 的玩家在队首,编号 n−1 的玩家在队尾。
队伍中共有 m 对不同的好友关系。具体而言,对于每个 i(0≤i≤m−1),玩家 x[i] 与玩家 y[i] 是好友,且满足 0≤x[i]<y[i]<n。好友关系是对称的。
考虑从玩家 s 开始的、长度为 k 的连续玩家序列(0≤s<n 且 1≤k≤n−s)。如果在该序列中,任意两名玩家之间都可以通过该组内的好友关系链相互到达,那么这组玩家构成一个规模为 k 的好友组。具体来说,玩家 s,s+1,…,s+k−1 构成规模为 k 的好友组,当且仅当对于任意满足 s≤u<v<s+k 的玩家 u 和 v,存在一列玩家 p[0],…,p[l−1],使得:
int n, m, t; int u[kMaxM], v[kMaxM], L[kMaxN], R[kMaxN]; std::pair<int, int> e[kMaxM * 2]; std::vector<std::pair<int, int>> seg;
structDSU { int fa[kMaxN], rnk[kMaxN]; std::vector<std::tuple<int, int, bool>> stk; voidinit(int n){ stk.clear(); for (int i = 1; i <= n; ++i) fa[i] = i, rnk[i] = 0; } intfind(int x){ for (; x != fa[x]; x = fa[x]) {} return x; } voidunionn(int x, int y){ int fx = find(x), fy = find(y); if (fx == fy) returnvoid(stk.emplace_back(-1, -1, 0)); if (rnk[fx] > rnk[fy]) std::swap(fx, fy); stk.emplace_back(fx, fy, rnk[fx] == rnk[fy]); fa[fx] = fy, rnk[fy] += (rnk[fx] == rnk[fy]); } voidundo(){ assert(stk.size()); auto [fx, fy, det] = stk.back(); stk.pop_back(); if (fx == -1) return; fa[fx] = fx, rnk[fy] -= det; } } dsu;
structDeque { int top; std::array<int, 2> stk[kMaxM * 2]; voidundo(){ --top, dsu.undo(); } voidclear(){ while (top) undo(); } voidlink(int id, int op){ dsu.unionn(e[id].first, e[id].second), stk[++top] = {id, op}; } voidrebuild(int op){ staticint top1, stk1[kMaxM * 2]; int del = 0; for (int i = top; i; --i) { if (!del && stk[i][1] == op) del = i; } if (!del) del = 1; top1 = 0; for (int i = top; i; --i) { if (i != del && stk[i][1] == 0) stk1[++top1] = stk[i][0]; } for (int i = 1; i <= top; ++i) { if (i != del && stk[i][1] == 1) stk1[++top1] = stk[i][0]; } clear(); int mid = top1 / 2; for (int i = 1, p1 = mid, p2 = mid + 1; i <= top1; ++i) { if (i & 1) link(stk1[p2++], 1); elselink(stk1[p1--], 0); } } voidrebuild(int x, int op){ staticint top1, stk1[kMaxM * 2]; staticint top2, stk2[kMaxM * 2]; int del = 0; for (int i = top; i >= x; --i) { if (!del && stk[i][1] == op) del = i; } top1 = top2 = 0; for (int i = top; i >= x; --i) { if (i != del) { if (stk[i][1] == 0) stk1[++top1] = stk[i][0]; else stk2[++top2] = stk[i][0]; } } while (top >= x) undo(); while (top1 > top2) link(stk1[top1--], 0); while (top2 > top1) link(stk2[top2--], 1); int tot = top1 + top2; for (int i = 1; i <= tot; ++i) { if (i & 1) link(stk1[top1--], 0); elselink(stk2[top2--], 1); } } voidpush_front(int id){ link(id, 0); } voidpush_back(int id){ link(id, 1); } voidpop_front(){ assert(top); int x = top; for (; x && stk[x][1] != 0; --x) {} // rebuild(0); if (!x || top - 2 * (top - x) <= 0) rebuild(0); elserebuild(top - 2 * (top - x), 0); } voidpop_back(){ assert(top); int x = top; for (; x && stk[x][1] != 1; --x) {} // rebuild(1); if (!x || top - 2 * (top - x) <= 0) rebuild(1); elserebuild(top - 2 * (top - x), 1); } } q;
voidsolve(int l, int r){ int id = -1; for (int i = 0; i <= r - l - 1; ++i) { if (dsu.find(l + i) != dsu.find(l + i + 1)) { id = l + i; break; } if (dsu.find(r - i - 1) != dsu.find(r - i)) { id = r - i - 1; break; } } if (id == -1) returnvoid(seg.emplace_back(l, r)); if (R[id] <= (L[l] + R[r]) / 2) { for (int i = L[l]; i <= R[id]; ++i) q.pop_front(); solve(id + 1, r); q.clear(); for (int i = L[l]; i <= R[id]; ++i) q.push_back(i); // std::cerr << "fuck " << l << ' ' << r << ' ' << id << ' ' << dsu.find(1) << ' ' << dsu.find(2) << '\n'; solve(l, id); } else { for (int i = R[r]; i > R[id]; --i) q.pop_back(); solve(l, id); q.clear(); // for (int i = R[r]; i > R[id]; --i) q.push_front(i); for (int i = R[id] + 1; i <= R[r]; ++i) q.push_back(i); solve(id + 1, r); } }
std::vector<int> partition_players(int n, int m, std::vector<int> X, std::vector<int> Y){ ::n = n, ::m = m; dsu.init(n + m); for (int i = 1; i <= m; ++i) { u[i] = X[i - 1] + 1, v[i] = Y[i - 1] + 1; e[++t] = {u[i], i + n}, e[++t] = {v[i], i + n}; } std::sort(e + 1, e + 1 + t); for (int i = 1; i <= n; ++i) { L[i] = std::lower_bound(e + 1, e + 1 + t, std::pair<int, int>{i, 0}) - e; R[i] = std::lower_bound(e + 1, e + 1 + t, std::pair<int, int>{i + 1, 0}) - e - 1; } for (int i = 1; i <= t; ++i) q.push_back(i); solve(1, n); std::sort(seg.begin(), seg.end()); std::vector<int> len; for (auto [l, r] : seg) len.emplace_back(r - l + 1); return len; }