[Aizu-1388] Counting Cycles

努力了一天没A掉?????????

 

转个题解吧,学会了高超的技巧,添加一堆非树边,判断能否成简单环

 又努力了一天,终于A了

#include<bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int MAXN=1e5+20;
struct Graph
{
	struct Edge
	{
		int v,nxt,id;
	}E[MAXN*2];
	int tot;
	int head[MAXN];
	void init()
	{
		tot=0;
		memset(head,-1,sizeof(head));
	}
	void addedge(int u,int v,int id=-1)
	{
		E[tot].v=v;E[tot].nxt=head[u];E[tot].id=id;
		head[u]=tot++;
		E[tot].v=u;E[tot].nxt=head[v];E[tot].id=id;
		head[v]=tot++;
	}
	void addedgeV(int u,int v,int id=-1)
	{
		addedge(u,v);
	}
	void debug(int n)
	{
		puts("DEBUG................");
		for(int i=1;i<=n;i++)
			for(int j=head[i];~j;j=E[j].nxt)
				printf("%d %d\n",i,E[j].v);
		puts("");
	}
}G,V,E;
struct vtree
{
	Graph *G,*V;
	int dep[MAXN],dfn[MAXN],fa[MAXN][20];
	int tag;
	bool key[MAXN];
	void init(Graph *g,Graph *v)
	{
		tag=0;
		G=g;G->init();
		V=v;V->init();
		memset(key,false,sizeof(key));
	}
	void dfs(int now,int f=1)
	{
		dfn[now]=++tag;dep[now]=dep[f]+1;fa[now][0]=f;
		for(int i=1;i<20;i++)
			fa[now][i]=fa[fa[now][i-1]][i-1];
		for(int i=G->head[now];~i;i=G->E[i].nxt)
		{
			int v=G->E[i].v;
			if(v==f) continue;
			dfs(v,now);
		}
	}
	int lca(int x,int y)
	{
		if(dep[x]<dep[y]) swap(x,y);
		for(int i=19;i>=0;i--)
			if(dep[fa[x][i]]>=dep[y])
				x=fa[x][i];
		if(x==y) return x;
		for(int i=19;i>=0;i--)
			if(fa[x][i]!=fa[y][i])
				x=fa[x][i],y=fa[y][i];
		return fa[x][0];
	}
	int stk[MAXN];
	void build(int v[],int sz)
	{
		int top=0;
		sort(v,v+sz,[&](const int &x,const int &y)->bool{return dfn[x]<dfn[y];});
	    int _nt=sz;
		for (int i=0;i<sz;i++)
		{
	        int x=v[i];
	        if(!top){stk[++top]=x;continue;}
	        int plca=lca(stk[top],x);
	        while(dep[stk[top-1]]>dep[plca]&&top>1)
			{
	            V->addedge(stk[top-1],stk[top]);
	            top--;
	        }
	        if(dep[plca]<dep[stk[top]])
			{
	            V->addedge(plca,stk[top]);
	            top--;
	        }
	        if(!top||dep[stk[top]]<dep[plca]) stk[++top]=plca;
	        stk[++top]=x;
	        if(!key[plca]){key[plca]=1;v[_nt++]=plca;}
	    }
	    while(top>1)
		{
	        V->addedge(stk[top-1],stk[top]);
	        top--;
	    }
		sz=_nt;
		for(int i=0;i<sz;i++)
			key[v[i]]=false;
	}
}vt;
int u[MAXN],v[MAXN],tmp[MAXN],fa[MAXN];
vector<int> sv;
struct Search
{
	Graph *G;
	int ans;
	bool book[MAXN],vis[MAXN];
	int in[MAXN],F[MAXN],cnt[MAXN];
	void init(Graph *g)
	{
		G=g;
		ans=0;
		memset(book,false,sizeof(book));
	}
	void solve(vector<int> vec)
	{
		int sz=vec.size();
		for(int i=1;i<(1<<sz);i++)
		{
			for(int j=0;j<sv.size();j++)
			{
				in[sv[j]]=0;book[sv[j]]=false;vis[sv[j]]=false;
				F[sv[j]]=sv[j];cnt[sv[j]]=0;
			}
			for(int j=0;j<sz;j++)
			{
				if((i>>j)&1)
				{
					int id=vec[j];
					update(u[id]);update(v[id]);
					in[u[id]]++;in[v[id]]++;
				}
			}
			for(int j=0;j<sv.size();j++)
				if(book[sv[j]])
					in[fa[sv[j]]]++,in[sv[j]]++;
			int rt=-1,num=0,tot=0;
			bool flag=true;
			for(int j=0;j<sv.size()&&flag;j++)
			{
				if(in[sv[j]]!=2&&in[sv[j]]!=0)
				{
					flag=false;
					break;
				}
				if(in[sv[j]]==2)
				{
					num++;rt=sv[j];
				}
			}
			if(rt==-1||!flag) continue;
			for(int j=0;j<sv.size();j++)
				if(book[sv[j]])
					Union(fa[sv[j]],sv[j]);
			for(int j=0;j<sz;j++)
			{
				if((i>>j)&1)
				{
					int id=vec[j];
					Union(u[id],v[id]);
				}
			}
			for(int j=0;j<sv.size();j++)
			{
				if(in[sv[j]]!=2) continue;
				int now=sv[j];
				now=Find(now);cnt[now]++;
				tot=max(tot,cnt[now]);
			}
			if(tot==num) ans++;
		}
	}
	int Find(int now)
	{
		if(now==F[now]) return now;
		return F[now]=Find(F[now]);
	}
	void Union(int u,int v)
	{
		u=Find(u);v=Find(v);
		if(u==v) return ;
		F[u]=v;
	}
	void update(int now)
	{
		if(now==1) return ;
		book[now]^=1;
		update(fa[now]);
	}
}sol;
bool book[MAXN],vis[MAXN];
void dfs(int now,int f=0)
{
	book[now]=true;
	for(int i=E.head[now];~i;i=E.E[i].nxt)
	{
		int v=E.E[i].v;
		if(book[v]) continue;
		G.addedge(now,v);
		vis[E.E[i].id]=true;
		dfs(v,now);
	}
}
void dfs2(int now,int f=0)
{
	fa[now]=f;sv.pb(now);
	for(int i=V.head[now];~i;i=V.E[i].nxt)
	{
		int v=V.E[i].v;
		if(v==f) continue;
		dfs2(v,now);
	}
}
vector<int> vec,ed;
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int n,m;
	scanf("%d%d",&n,&m);
	vt.init(&G,&V);
	E.init();
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u[i],&v[i]);
		E.addedge(u[i],v[i],i);
	}
	dfs(1);vt.dfs(1);
	int tot=0;
	tmp[tot++]=1;
	for(int i=1;i<=m;i++)
	{
		if(!vis[i])
		{
			ed.pb(i);
			tmp[tot++]=u[i];
			tmp[tot++]=v[i];
		}
	}
	sort(tmp,tmp+tot);
	tot=unique(tmp,tmp+tot)-tmp;
	vt.build(tmp,tot);
	dfs2(1);
	for(int i=0;i<ed.size();i++)
	{
		int id=ed[i];
		V.addedge(u[id],v[id],i);
	}
	sol.init(&V);
	sol.solve(ed);
	printf("%d\n",sol.ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值