原题传送门
构造题
首先对于条件进行转化–>
(
p
+
1
)
(
q
+
1
)
>
n
(p+1)(q+1)>n
(p+1)(q+1)>n
然后就是构造一个
p
,
q
p,q
p,q出来
考虑一种做法:
- 在图中选出度数最小的点,这个度数记为 d i d_i di
- 将该点以及与该点直接相连的点删去
- 重复上述过程直到无点为止
- 取出 d i d_i di最大的时刻的图作为第一个点集,此时热闹度 p = d i p=d_i p=di,取所有操作1选择的点作为第二个点集就行了
考虑证明正确性:
设操作1共进行了
q
q
q次,
d
m
a
x
=
m
a
x
(
d
i
)
dmax=max(d_i)
dmax=max(di)
得到
∑
i
=
1
q
(
d
i
+
1
)
=
n
\sum_{i=1}^{q}(d_i+1)=n
∑i=1q(di+1)=n,
p
=
d
m
a
x
p=dmax
p=dmax
那么
(
p
+
1
)
q
>
=
∑
i
=
1
q
(
d
i
+
1
)
=
n
(p+1)q>=\sum_{i=1}^{q}(d_i+1)=n
(p+1)q>=∑i=1q(di+1)=n
即
(
p
+
1
)
(
q
+
1
)
>
n
(p+1)(q+1)>n
(p+1)(q+1)>n
得证
至于怎么维护这个删点并且修改点集中度数,每次还要找最小,用
s
t
d
:
:
s
e
t
std::set
std::set
然后我这个
s
e
t
set
set是新学的,不明白为什么
o
p
e
r
a
t
o
r
operator
operator写结构体里要把大小关系反一下?难道是
s
e
t
set
set的特点?
Code:
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
struct Edge{
int to, next;
}edge[maxn << 1];
int num, head[maxn], n, m, cnt, len, q[maxn], print[maxn], d[maxn];
struct node{
int u, d;
}a[maxn];
bool operator < (node a, node b){ return a.d == b.d ? a.u < b.u : a.d < b.d; }
typedef set<node> :: iterator iter;
set<node> S;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
void addedge(int x, int y){ edge[++num] = (Edge){y, head[x]}, head[x] = num; }
int main(){
int Q = read();
while (Q--){
n = read(), m = read(), cnt = len = num = 0;
memset(head, 0, sizeof(head));
for (int i = 1; i <= n; ++i) d[i] = 0, a[i] = (node){i, 0};
for (int i = 1; i <= m; ++i){
int x = read(), y = read();
addedge(x, y), addedge(y, x);
++a[x].d, ++a[y].d, ++d[x], ++d[y];
}
for (int i = 1; i <= n; ++i) S.insert(a[i]);
int maxd = -1, pos = 0;
while (!S.empty()){
int u = (*S.begin()).u;
if (d[u] > maxd) maxd = d[u], pos = len;
S.erase(S.begin());
q[++len] = u, print[++cnt] = u;
for (int i = head[u]; i; i = edge[i].next){
int v = edge[i].to;
iter it = S.find((node){v, d[v]});
if (it == S.end()) continue;
S.erase(it), q[++len] = v;
for (int j = head[v]; j; j = edge[j].next){
int k = edge[j].to;
it = S.find((node){k, d[k]});
if (it == S.end()) continue;
S.erase(it), S.insert((node){k, --d[k]});
}
}
}
printf("%d ", len - pos);
for (int i = pos + 1; i <= len; ++i) printf("%d ", q[i]);
puts("");
printf("%d ", cnt);
for (int i = 1; i <= cnt; ++i) printf("%d ", print[i]);
puts("");
}
return 0;
}