题解 2D
考场上题读假了……居然还是拿了35pts
- 求一张无向图内价值最大的 \(k-degree\) 子图,要求每个点在子图内的度数至少为 \(k\)
首先从 \(k\) 最大的 \(k-degree\) 子图不断扩展的思路很好想
但难点在于如何找到最大的 \(k-degree\) 子图,及该按什么顺序把它们加进去
发现 \(k+1\) 的图肯定是 \(k\) 时的图的子图
考虑 \(1-degree\) 子图即原图的连通块,很好确定
那要推到 \(2-degree\),就是将度数最小的点删掉
于是可以用这种方式处理出每个点反着推应该在什么时候加入子图 - 延迟删除优先队列的优化:当值域不大的时候可以换成延迟删除的桶排序
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LIM 1000010
#define ll long long
#define reg register int
#define fir first
#define sec second
#define make make_pair
#define pb push_back
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
ll N, M, B;
int head[LIM], size, tot, tim[LIM], cnt[LIM], mcnt, deg[LIM];
int maxk; ll maxn=-1e18;
struct point{int id, tim; inline void build(int a, int b) {id=a; tim=b;}}p[LIM];
int fa[LIM], ncnt[LIM], ecnt[LIM], bcnt[LIM];
bool del[LIM], vis[LIM], pdel[LIM], vis2[LIM];
queue<int> q1, q2;
set< pair<int, int> > s;
vector<int> v[LIM];
struct edge{int to, next;}e[LIM<<1];
inline void add(int s, int t) {e[++size].to=t; e[size].next=head[s]; head[s]=size;}
inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}
signed main()
{
freopen("kdgraph.in", "r", stdin);
freopen("kdgraph.out", "w", stdout);
memset(head, -1, sizeof(head));
n=read(); m=read(); M=read(); N=read(); B=read();
for (int i=1,u,v; i<=m; ++i) {
u=read(); v=read();
add(u, v); add(v, u);
mcnt=max(mcnt, ++cnt[u]);
mcnt=max(mcnt, ++cnt[v]);
}
#if 0
for (int i=1; i<=n; ++i) s.insert(make(cnt[i], i));
for (int i=1; i<=mcnt; ++i) {
// cout<<"i: "<<i<<endl;
while (s.size()) {
auto it=s.begin();
// cout<<"it: "<<it->fir<<' '<<it->sec<<endl;
if (it->fir<=i) {
tim[it->sec]=i;
int u=it->sec;
s.erase(it);
pdel[u]=1;
for (int j=head[u],v; ~j; j=e[j].next) {
v = e[j].to;
if (pdel[v]) continue;
auto it=s.find(make(cnt[v], v));
// cout<<"cge: "<<v<<endl;
assert(it!=s.end());
s.erase(it);
--cnt[v];
// cout<<"v: "<<v<<' '<<cnt[v]<<endl;
if (cnt[v]<=i) tim[v]=i;
if (cnt[v]>0) s.insert(make(cnt[v], v));
}
}
else break;
}
}
#else
for (int i=1; i<=n; ++i) v[cnt[i]].pb(i);
for (int i=1; i<=mcnt; ++i) {
for (auto j:v[i]) if (cnt[j]<=i && !vis2[j]) q2.push(j), vis2[j]=1;
while (q2.size()) {
int u=q2.front(); q2.pop();
tim[u]=i;
pdel[u]=1;
for (int k=head[u],v2; ~k; k=e[k].next) {
v2 = e[k].to;
if (pdel[v2]) continue;
if (--cnt[v2]<=i) {
tim[v2]=i;
if (!vis2[v2]) q2.push(v2), vis2[v2]=1;
}
else v[cnt[v2]].pb(v2);
}
}
}
#endif
for (int i=1; i<=n; ++i) p[i].build(i, tim[i]); //, cout<<"p: "<<i<<' '<<tim[i]<<endl;
for (int i=1; i<=n; ++i) fa[i]=i, ncnt[i]=1;
sort(p+1, p+n+1, [](point a, point b){return a.tim>b.tim;});
int pos1=1,pos2=1;
for (; pos2<=n; ++pos2,pos1=pos2) {
while (pos2<n && p[pos2].tim==p[pos2+1].tim) ++pos2;
for (int i=pos1; i<=pos2; ++i) if (~head[p[i].id]) {
int f=find(p[i].id);
if (!vis[f]) {q1.push(f); vis[f]=1;}
for (int j=head[p[i].id],v,f2; ~j; j=e[j].next) {
v = e[j].to;
f2=find(v);
if (tim[v]>=p[i].tim && f!=f2) {
fa[f2]=f; del[f2]=1;
ncnt[f]+=ncnt[f2];
ecnt[f]+=ecnt[f2];
bcnt[f]+=bcnt[f2];
}
}
}
for (int i=pos1; i<=pos2; ++i) {
int f=find(p[i].id);
for (int j=head[p[i].id],v; ~j; j=e[j].next) {
v = e[j].to;
if (tim[v]>p[i].tim) --bcnt[f], ecnt[f]+=2;
else if (tim[v]==p[i].tim) ++ecnt[f];
else ++bcnt[f];
}
}
while (q1.size()) {
int u=q1.front(); q1.pop();
if (del[u]) continue;
vis[u]=0;
// cout<<"u: "<<u<<endl;
// cout<<"k: "<<p[pos1].cnt<<' '<<ncnt[u]<<' '<<ecnt[u]<<' '<<bcnt[u]<<endl;
ll tem=M*(ecnt[u]/2)-N*ncnt[u]+B*bcnt[u];
if (tem>maxn) maxn=tem, maxk=p[pos1].tim;
//q2.push(u);
}
// swap(q1, q2);
}
printf("%d %lld\n", maxk, maxn);
return 0;
}