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

时间:2021-03-19 19:45:47

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维护了一下最大= =因为链表的话感觉很麻烦写= =