「SDOI2019」热闹的聚会与尴尬的聚会

#3113. 「SDOI2019」热闹的聚会与尴尬的聚会

Summarize

震惊!tth37居然……

给定一个图 $G$, 要求在图中选出一些点组成两个互不相关的子图 $P$,$Q$,其中子图 $Q$ 为原图的一个独立集。记 $P$ 中的节点最小度数为 $p$,$q=|Q|$。要求 $\lfloor\frac{n}{p+1}\rfloor\le q$ 且 $\lfloor\frac{n}{q+1}\rfloor\le p$,输出一种可行方案。

$n\le 1e5,m\le 1e5$

Solution

对题意进行转化,$\frac{n}{p+1}<\lfloor\frac{n}{p+1}\rfloor+1\le q+1$,$n<(p+1)(q+1)$。

考虑如下构造方法:第 $i$ 次操作中选取当前剩余图中度数最小的节点,记其度数为 $d_i$、节点编号为 $a_i$,将该节点及其相邻的节点删去。重复上述操作,直至图中没有剩余节点,设该操作重复 $q$ 次。

不难发现 $\lbrace a_i\rbrace$ 为独立集,可以将 $\lbrace a_i\rbrace$ 加入集合 $Q$。取 $d_m=\max\lbrace d_i\rbrace$,换言之剩余图中最小节点度数的最大值为 $d_m$。将第 $m$ 次及以后删除的点加入集合 $P$,则 $p=d_m$。此时 $q\times (d_m+1)\ge n$,原式显然成立。

用线段树维护度数最小的节点。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <bits/stdc++.h>
void readint() {}
template<class T1, class ...T2>
void readint(T1 &i, T2&... rest){
i=0;char c;bool f=false;
while (!isdigit(c=getchar())) f=c=='-';
do i=(i<<3)+(i<<1)+c-'0'; while (isdigit(c=getchar()));
if (f) i=-i;
readint(rest...);
}
using namespace std;

const int MAXN = 10005;
const int INF = 0x3f3f3f3f;

int t, n, m, d[MAXN], sum;
bool del[MAXN];
vector<int> G[MAXN], P[MAXN], Q;

struct Segment_Tree {
#define lson(u) node[u].l
#define rson(u) node[u].r
#define val(u) node[u].val
#define pos(u) node[u].pos
struct Node {
int l, r, val, pos;
} node[MAXN << 2];
int R, cnt;
void pushup(int u) {
val(u) = min(val(lson(u)), val(rson(u)));
if (val(lson(u)) == val(u)) pos(u) = pos(lson(u));
else pos(u) = pos(rson(u));
}
void build(int& u, int l, int r) {
u = ++cnt;
if (l == r) {
val(u) = d[l];
pos(u) = l;
return;
}
int mid = (l + r) >> 1;
build(lson(u), l, mid), build(rson(u), mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, int p, int val) {
if (l == r) {
val(u) += val;
return;
}
int mid = (l + r) >> 1;
if (p <= mid) modify(lson(u), l, mid, p, val);
else modify(rson(u), mid + 1, r, p, val);
pushup(u);
}
} T;

int main() {
readint(t);
while (t--) {
readint(n, m);
for (int i = 1; i <= m; ++i) {
int u, v;
readint(u, v);
G[u].push_back(v), G[v].push_back(u);
d[u]++, d[v]++;
}
T.build(T.R, 1, n);
int max_val = 0, max_pos = 0, cur_pos = 0;
while (sum ^ n) {
cur_pos++;
int u = T.pos(T.R);
if (T.val(T.R) > max_val) {
max_val = T.val(T.R), max_pos = cur_pos;
}
Q.push_back(u), P[cur_pos].push_back(u);
del[u] = 1, T.modify(T.R, 1, n, u, INF), sum++;
for (auto v : G[u]) {
if (del[v]) continue;
P[cur_pos].push_back(v);
del[v] = 1, T.modify(T.R, 1, n, v, INF), sum++;
for (auto w : G[v]) {
if (del[w]) continue;
T.modify(T.R, 1, n, w, -1);
}
}
}
int p_cnt = 0;
for (int i = max_pos; i <= cur_pos; ++i)
p_cnt += P[i].size();
printf("%d ", p_cnt);
for (int i = max_pos; i <= cur_pos; ++i) {
for (auto u : P[i])
printf("%d ", u);
}
puts("");
printf("%d ", cur_pos);
for (auto u : Q)
printf("%d ", u);
puts("");
T.cnt = 0;
for (int i = 1; i <= n; ++i)
G[i].clear(), P[i].clear();
Q.clear();
memset(del, 0, sizeof(del));
memset(d, 0, sizeof(d));
sum = 0;
}
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×