[仙人掌 并查集 组合计数] BZOJ 4450 [Neerc2015]Cactus Jubilee

题意:给你一棵仙人掌,求有多少种方案使得移动一条边之后的图形仍是仙人掌。

题解:



#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=50005;

struct edge{
	int u,v,f,next;
}G[N<<3];
int head[N],inum=1;

inline void add(int u,int v,int p){
	G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

int n,m; ll ans;

int pre[N],clk;
int fat[N],fp[N],size[N],nxt[N];

namespace Tset{
	int fat[N],size[N],rank[N];
	inline void init(int n){
		for (int i=1;i<=n;i++)
			fat[i]=i,size[i]=1;
	}
	inline int Fat(int u){
		return u==fat[u]?u:fat[u]=Fat(fat[u]);
	}
	inline void Union(int x,int y){
		x=Fat(x); y=Fat(y); if (x==y) return;
		if (rank[x]>rank[y]) swap(x,y);
		if (rank[x]==rank[y]) rank[y]++;
		fat[x]=y; size[y]+=size[x];
	}
	inline int Size(int u){
		return size[Fat(u)];
	}
}

#define V G[p].v
inline void dfs(int u,int fa){
	pre[u]=++clk; fat[u]=fa;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
		{
			if (!pre[V]){
				fp[V]=p,dfs(V,u);
			}
			else if (pre[V]<pre[u])
			{
				G[p].f=G[p^1].f=1;
				int i;
				nxt[u]=V;
				for (i=u;fat[i]!=V;i=fat[i])
				{
					nxt[fat[i]]=i;
					G[fp[i]].f=G[fp[i]^1].f=1;
				}
//				nxt[fat[i]]=i;
				G[fp[i]].f=2; G[fp[i]^1].f=1;
			}
		}
}

inline void rebuild(int u,int fa){
	size[u]=1;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			if (!G[p].f)
			{
				rebuild(V,u),size[u]+=size[V];
				ans+=(ll)size[V]*(n-size[V])-1;
			}
			else if (G[p].f==2)
				rebuild(V,u),size[u]+=size[V];
	if (nxt[u] && pre[nxt[u]]>pre[u])
		rebuild(nxt[u],u),size[u]+=size[nxt[u]];
}

ll sum[N],tot;

int main()
{
	int iu,iv;
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	read(n); read(m);
	for (int i=1;i<=m;i++)
		read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
	dfs(1,0);
	rebuild(1,0);
	Tset::init(n);
	for (int u=1;u<=n;u++)
		for (int p=head[u];p;p=G[p].next)
			if (!G[p].f)
				Tset::Union(u,V);
	for (int i=1,s;i<=n;i++)
		if (Tset::Fat(i)==i && (s=Tset::Size(i))>2)
			sum[i]=s*(s-1)/2-(s-1),tot+=sum[i];
	for (int u=1;u<=n;u++)
		for (int p=head[u];p;p=G[p].next)
			if (G[p].f==2)
			{
				ll ttot=tot;
				int len=1;
				ll tsum=Tset::Size(u); 
				ttot-=sum[Tset::Fat(u)];
				for (int i=V;i!=u;i=nxt[i])
					len++,tsum+=Tset::Size(i),ttot-=sum[Tset::Fat(i)];
				ans+=(tsum*(tsum-1)/2-(tsum-1)-1)*len;
				ans+=len*ttot;
			}
	printf("%lld\n",ans);
	return 0;
}


UPD160712

BZ上的代码


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> abcd;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=50005;

struct edge{
	int u,v,f,next;
}G[N<<3];
int head[N],inum=1;

inline void add(int u,int v,int p){
	G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

int n,m; ll ans;

int pre[N],clk;
int fat[N],fp[N],size[N],nxt[N];

namespace Tset{
	int fat[N],size[N],rank[N];
	inline void init(int n){
		for (int i=1;i<=n;i++)
			fat[i]=i,size[i]=1;
	}
	inline int Fat(int u){
		return u==fat[u]?u:fat[u]=Fat(fat[u]);
	}
	inline void Union(int x,int y){
		x=Fat(x); y=Fat(y); if (x==y) return;
		if (rank[x]>rank[y]) swap(x,y);
		if (rank[x]==rank[y]) rank[y]++;
		fat[x]=y; size[y]+=size[x];
	}
	inline int Size(int u){
		return size[Fat(u)];
	}
}

#define V G[p].v
inline void dfs(int u,int fa){
	pre[u]=++clk; fat[u]=fa;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
		{
			if (!pre[V]){
				fp[V]=p,dfs(V,u);
			}
			else if (pre[V]<pre[u])
			{
				G[p].f=G[p^1].f=1;
				int i;
				nxt[u]=V;
				for (i=u;fat[i]!=V;i=fat[i])
				{
					nxt[fat[i]]=i;
					G[fp[i]].f=G[fp[i]^1].f=1;
				}
				G[fp[i]].f=2; G[fp[i]^1].f=1;
			}
		}
}

inline void rebuild(int u,int fa){
	size[u]=1;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			if (!G[p].f)
			{
				rebuild(V,u),size[u]+=size[V];
				ans+=(ll)size[V]*(n-size[V])-1;
			}
			else if (G[p].f==2)
				rebuild(V,u),size[u]+=size[V];
	if (nxt[u] && pre[nxt[u]]>pre[u])
		rebuild(nxt[u],u),size[u]+=size[nxt[u]];
}

ll sum[N],tot;

int main()
{
	int iu,iv,k;
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	read(n); read(m);  
	for (int i=1;i<=m;i++)  
	{  
		read(k); read(iu);  
		for (int j=2;j<=k;j++)
			read(iv),add(iu,iv,++inum),add(iv,iu,++inum),iu=iv;
	}  
	dfs(1,0);
	rebuild(1,0);
	Tset::init(n);
	for (int u=1;u<=n;u++)
		for (int p=head[u];p;p=G[p].next)
			if (!G[p].f)
				Tset::Union(u,V);
	for (int i=1,s;i<=n;i++)
		if (Tset::Fat(i)==i && (s=Tset::Size(i))>2)
			sum[i]=(ll)s*(s-1)/2-(s-1),tot+=sum[i];
	for (int u=1;u<=n;u++)
		for (int p=head[u];p;p=G[p].next)
			if (G[p].f==2)
			{
				ll ttot=tot,len=1,tsum=Tset::Size(u); 
				ttot-=sum[Tset::Fat(u)];
				for (int i=V;i!=u;i=nxt[i])
					len++,tsum+=Tset::Size(i),ttot-=sum[Tset::Fat(i)];
				ans+=(tsum*(tsum-1)/2-(tsum-1)-1)*len;
				ans+=len*ttot;
			}
	printf("%lld\n",ans);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值