题解 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;
}
posted @ 2021-09-20 19:27  Administrator-09  阅读(0)  评论(0编辑  收藏  举报