您的位置:首页 > Web前端 > JavaScript

[BZOJ1016]JSOI2008最小生成树计数 |kruskal|乘法原理|dfs

2015-04-17 09:48 537 查看
看起来很有可做性。。很容易yy出来两个东西,一是最小生成树上各权值边的数量是一定的,二是每个权值的边确定的并查集是一定的。根据这两个我们可以先跑一遍最小生成树把各权值边的数量搞出来,然后因为数据范围小,直接爆搜每种权值边的方案数然后乘起来就行了,往下搜的时候要把整个并查集备份下来。。

#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
struct edge{
int e,next;
}ed[500005];
const int maxn=500005;
int n,m,k,i,j,u,v,ne=0,sum,ans[maxn],in[maxn],a[maxn],pre[maxn],ruin[maxn];
void add(int s,int e)
{
ed[++ne].e=e;ed[ne].next=a[s];a[s]=ne;
}
int getfa(int x)
{
if (pre[x]==x) return x;
pre[x]=getfa(pre[x]);
return pre[x];
}
void merge(int a,int b)
{
int fa=getfa(a),fb=getfa(b);
if (fa!=fb)
{
pre[fa]=fb;sum--;
}
}
int main()
{
//	freopen("1015.in","r",stdin);
scanf("%d%d",&n,&m);
memset(a,0,sizeof(a));
for (i=0;i<n;i++) pre[i]=i;
for (i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
memset(in,0,sizeof(in));
scanf("%d",&k);
sum=n-k;
for (i=1;i<=k;i++)
{
scanf("%d",&u);
in[u]=1;ruin[i]=u;
}
for (i=0;i<n;i++)
if (!in[i])
for (j=a[i];j;j=ed[j].next)
if (!in[ed[j].e]) merge(i,ed[j].e);
ans[k+1]=sum;
for (i=k;i>0;i--)
{
sum++;in[ruin[i]]=0;
for (j=a[ruin[i]];j;j=ed[j].next)
if (!in[ed[j].e]) merge(ruin[i],ed[j].e);
ans[i]=sum;
}
for (i=1;i<=k+1;i++)
printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: