题解 [UOJ #461] 新年的Dog划分

传送门

艹感觉自己在划大水
所以这题是水过去的

我把题读成了什么呢?每次选若干个点对,将这些点对及与之相关的边全部删除
于是自闭一上午
等通过题解意识到自己题读错了已经没意愿再好好想题了

那么暴力可以枚举左部点集,仅保留两点集之间的边看是否连通
因为保证是二分图了嘛,可以反证这样合法(水博

然后一个好一点的暴力是不断删边
不影响连通性就删,影响就留着,这样可以找到一棵生成树
那么对生成树黑白染色即可
check 合法就是 ban 掉左右部点之间除生成树上的边,看生成树上是否有环(能不能再从树上 ban 条边)

然后删边可以二分下一个树边在哪,但是 \(\log n^2\approx2\log n\) 过不去
于是对每个点做这个事情,就只需要在 \(n\) 条边中二分了
然后你发现这样二分每个点的最后一次二分可能不对应一条树边,所以又带了一个 2 的常数
我的解决方法是每次二分之前 check 一下剩下的边都删掉是否合法
这样复杂度应该是 \(O(n\log n+2n+n)\)\(2n\) 是上面这个 check,最后那个 \(n\) 是回代找环
貌似正解是 BFS 处理什么的(咕

点击查看代码
#include <bits/stdc++.h>
#include "graph.h"
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back

int n;
bool vis[N], col[N];
vector<int> to[N], ans;
map<pair<int, int>, bool> intr;
vector<pair<int, int>> base, tree;
bool query(std::vector<std::pair<int, int>> banned_edges);

void dfs(int u, int c) {
	// cout<<"dfs: "<<u<<endl;
	vis[u]=1; col[u]=c;
	vector<pair<int, int>> sta, t;
	for (int i=0; i<n; ++i) if (!vis[i]) sta.pb({u, i});
	if (!sta.size()) return ;
	int lst=0;
	while (lst<=sta.size()-1) {
		int l=lst, r=sta.size()-1, mid;
		t=base;
		for (int j=lst; j<sta.size(); ++j) t.pb(sta[j]);
		if (query(t)) break;
		while (l<=r) {
			mid=(l+r)>>1; t=base;
			for (int j=lst; j<=mid; ++j) t.pb(sta[j]);
			if (query(t)) l=mid+1;
			else r=mid-1;
		}
		if (l>=sta.size()) break;
		tree.pb(sta[l]), to[u].pb(sta[l].sec);
		for (int i=lst; i<l; ++i) base.pb(sta[i]);
		lst=l+1;
	}
	for (auto it:to[u]) if (!vis[it]) dfs(it, col[u]^1);
}

vector<int> check_bipartite(int vsize) {
	n=vsize;
	dfs(0, 0);
	assert(tree.size()==n-1);
	// cout<<"tree: "; for (auto it:tree) cout<<"("<<it.fir<<','<<it.sec<<") "; cout<<endl;
	for (auto it:tree) intr[{min(it.fir, it.sec), max(it.fir, it.sec)}]=1;
	vector<pair<int, int>> tem, t;
	for (int i=0; i<n; ++i)
		for (int j=i+1; j<n; ++j) if (col[i]!=col[j])
			if (intr.find({i, j})==intr.end())
				tem.pb({i, j});
	for (auto it:tree) {
		t=tem; t.pb(it);
		if (query(t)) return vector<int>();
	}
	vector<int> ans;
	for (int i=0; i<n; ++i) if (col[i]) ans.pb(i);
	return ans;
}
posted @ 2022-05-03 11:50  Administrator-09  阅读(3)  评论(0编辑  收藏  举报