bzoj1006 弦图相关

弦图啊。。。鬼畜的东西。。。害怕。水弱如我当然不能理解这种神奇东西了所以有错的话求指出啊orz。。

点集V的诱导子图:E={(u,v)| u属于V,v属于V}。

弦图:没有长度超过3的无弦环的图。

单纯点:与该点相邻的点的诱导子图是个团。

完美消除序列:点的排列p1,p2..pn,使得对于每一个pi,pi在pi+1~pn中的诱导子图中是个单纯点。

定理:当且仅当一个图有完美消除序列时它是弦图。

(证明:1.有完美消除序列的图是弦图。假设不是,那么存在一个长度>3的无弦环,设它在完美消除序列中最靠前的点

是v,则必然存在两个环上的点v1,v2,(v1>v,v2>v),使得有边v->v1,v->v2,那么根据完美消除序列的定义,v1到v2有边。

矛盾。所以有完美消除序列的图是弦图。)

2.弦图有完美消除序列。首先,弦图至少有一个单纯点。弦图子集的诱导子图依然是弦图。1个点时存在完美消除序列。

于是将一个弦图拆成子弦图+单纯点,该弦图的完美消除序列就是单纯点+子弦图的完美消除序列。)

求完美消除序列:最大势算法。从n到1给点标号,每次找相邻的已标号点数目最多的未标号点标上即可。

检验完美消除序列:倒着来,设{pi+1...pn}中与pi相邻的点集是{pj1,pj2..pjk},则pj1~{pj2..pjk}都有边。

检验弦图:求一波完美消除序列,然后判断是不是合法。

最小染色数=最大团数:倒着来,每次mex后继,找到能染的最小颜色。

最大独立集=最小团覆盖数:正着来能取则取。

证明不会。。。码一下留待填坑。(有一种会证不出的不祥预感。。证不出的话我orz一下就跑

#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (int x=y; x<=z; x++)
#define downrep(x,y,z) for (int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (int x=hed[y]; ~x; x=edge[x].nex)
inline int read(){
	int x=0; int w=0; char ch=0;
	while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
	while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return w? -x:x;
}
const int N=100005;
const int M=1000005;
int vis[N],a[N],col[N],label[N],hed[N],nedge,n,m,tr[N<<2];
priority_queue< pair<int,int> > q;
struct Edge{ int to,nex; }edge[M<<1];
void addedge(int a,int b){ edge[nedge].to=b; edge[nedge].nex=hed[a]; hed[a]=nedge++; }
void Maximum_Cardinary(){
	rep(i,1,n) q.push(make_pair(0,i)); int cnt;
	for(cnt=n; cnt>=1; ){
		int x=q.top().second; q.pop(); if (vis[x]) continue;
	    vis[x]=cnt--; 
		repedge(i,x){ int v=edge[i].to; 
		   if (!vis[v]) q.push(make_pair(++label[v],v));
		} 
	}
    rep(i,1,n) a[vis[i]]=i;
}
#define mid ((l+r)>>1)
#define lc (nod<<1)
#define rc ((nod<<1)|1)
void add(int l,int r,int nod,int x,int v){
	if (l==r){ tr[nod]+=v; return; }
	if (x<=mid) add(l,mid,lc,x,v); else add(mid+1,r,rc,x,v);
	tr[nod]=tr[lc]+tr[rc];
}
int query(int l,int r,int nod){
	if (l==r) return l;
	return (tr[lc]!=(mid-l+1))? query(l,mid,lc):query(mid+1,r,rc);
}
int Color(){
	downrep(i,n,1){
		repedge(j,a[i]){ 
		   int v=edge[j].to;
		   if (col[v]) add(1,n,1,col[v],1);
		}
	    int x=query(1,n,1);
	    repedge(j,a[i]){
	       int v=edge[j].to;
	       if (col[v]) add(1,n,1,col[v],-1);
		}
		col[a[i]]=x; 
	}
	int ans=0; rep(i,1,n) ans=max(ans,col[i]); 
	return ans;
}
int main(){
	n=read(); m=read(); nedge=0; ms(hed,-1,hed);
	rep(i,1,m){ int a=read(); int b=read(); addedge(a,b); addedge(b,a);	}
    Maximum_Cardinary(); int ans=Color();
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/shiveringkonnyaku/article/details/82838413