zl程序教程

您现在的位置是:首页 >  其它

当前栏目

【BZOJ】1006: [HNOI2008]神奇的国度

神奇 BZOJ
2023-09-27 14:22:21 时间

http://www.lydsy.com/JudgeOnline/problem.php?id=1006

题意:在一个弦图中找最少染色数。(n<=10000, m<=1000000)

#include <bits/stdc++.h>
using namespace std;
const int N=10005, M=1000005;
int n, m, ihead[N], tag[N], cnt, pos[N];
bool vis[N];
struct E { int next, to; }e[M<<1];
void add(int u, int v) {
	e[++cnt]={ihead[u], v}; ihead[u]=cnt;
	e[++cnt]={ihead[v], u}; ihead[v]=cnt;
}
#define pii pair<int, int> 
#define mkpii make_pair<int, int>
set<pii> s;
inline int getmx() {
	set<pii>::iterator it=s.end(); --it;
	int ret=(*it).second;
	s.erase(s.find(mkpii((*it).first, ret)));
	return ret;
}
inline void fix(int x) {
	s.erase(s.find(mkpii(tag[x], x)));
	++tag[x];
	s.insert(mkpii(tag[x], x));
}
int getans() {
	int ret=0;
	for(int i=1; i<=n; ++i) s.insert(mkpii(0, i));
	for(int now=n; now; --now) {
		int x=getmx(), ans=1;
		pos[x]=now;
		for(int i=ihead[x]; i; i=e[i].next) if(!pos[e[i].to]) fix(e[i].to);
		for(int i=ihead[x]; i; i=e[i].next) if(pos[e[i].to]>pos[x] && !vis[e[i].to]) ++ans, vis[e[i].to]=1;
		for(int i=ihead[x]; i; i=e[i].next) if(pos[e[i].to]>pos[x]) vis[e[i].to]=0;
		ret=max(ret, ans);
	}
	return ret;
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i=0; i<m; ++i) {
		int x, y;
		scanf("%d%d", &x, &y);
		add(x, y);
	}
	printf("%d\n", getans());
	return 0;
}

  

题解:

定理1:色数>=团数

定理2:最小色数=极大团数

定理1不会证QAQ(如此显然的东西竟然没看出来?

定理2挺简单的,看cdq论文= =

所以我们找最大的团就行了= =

于是就完了= =

用set维护了一下最大= =因为链表的话感觉很麻烦写= =