其他分享
首页 > 其他分享> > Kuglarz の tj

Kuglarz の tj

作者:互联网

Kuglarz

我们可以发现,我们要确定 i 里面有没有东西,有两种方法:

1.直接看 ( i , i )
2.看 ( i , j ) 和 ( i + 1 , j ) 
我们可以把点变成边权, i 变成 i − 1 到 i的一条边。( 对于(i,i)这种自环情况可以设置一个虚点0 )
那我们就发现我们要让最小的边权使得所有的点都被连起来。

如果我们知道每一个位置是否有小球,那么就可以知道区间[ 0 , i ] (1≤i≤n)的奇偶性。

相反,如果我们知道区间 [ 0 , i ] (1≤i≤n)的奇偶性,那么我们就可以知道每个位置是否有小球。所以我们只用花费最小代价求知每个[0,i]区间的奇偶性。

如果我们知道区间[0,i-1][i,j]的奇偶性,就可以知道[0,j]的奇偶性。同理,如果知道[0,j][i,j]的奇偶性,我们就可以知道[0,i-1]的奇偶性。

位置0是我们虚构的节点,该位置上一定没有小球,所以[0,0]为偶。

对于一次询问[i,j],我们将[0,i-1][0,j]之间连一条权值为ci,j的边,表示知道其中一个,花费ci,j​代价可以知道另一个。

只要保证所有点和[0,0]联通,即整个图联通,即可保证知道所有[0,i]的奇偶性,就可以知道所有位置上是否有小球。

图已经建好了,直接求最小生成树即可。边数较多,建议使用Prim,但笔者很菜只会kruscal

 #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Edge {
	ll u,v,w;
}edge[5000005];
ll fa[5000005];
bool cmp(Edge x,Edge y) {
	return x.w<y.w;
}
ll Find(ll x) {
	if(x==fa[x]) return x;
	return fa[x]=Find(fa[x]);
}
int main() {
	//freopen("kuglurz.in","r",stdin);
	//freopen("kuglurz.out","w",stdout); 
	ll n,a,idx=0;
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++)
		fa[i]=i;
	for(ll i=1;i<=n;i++) {
		for(ll j=i;j<=n;j++) {
			scanf("%lld",&a);
			edge[++idx].u=i-1,edge[idx].v=j,edge[idx].w=a;
		}
	}
	sort(edge+1,edge+idx+1,cmp);
	ll sum=0,cnt=0;
	for(ll i=1;i<=idx;i++) {
		ll x=Find(edge[i].u),y=Find(edge[i].v);
		if(x==y) continue;
		cnt++;
		fa[x]=y;
		sum+=edge[i].w; 
		if(cnt==n) break;
	}
	printf("%lld",sum);
	return 0;
}

 

标签:ll,小球,Kuglarz,奇偶性,Edge,tj,我们,知道
来源: https://www.cnblogs.com/pangtuan666/p/16533180.html