P5994 [PA2014]Kuglarz 最小生成树

挺有趣的一道题。

显然,我们如果知道某个位置的奇偶性,我们就能知道某个位置是否有小球(题目说明一个位置最多只有一个小球)。

我们有两种方法可以知道位置 \(i\) 的奇偶性,直接询问位置 \(i\) 的奇偶性或者间接询问。

所谓的间接询问就比如先问 \([i,j]\) 再问 \([i+1,j]\) 的奇偶性。

再举个栗子就比如先问 \([i,j]\) 然后问 \([i+1,k]\) (其中 \(k<j\) )再问 \([k+1,j]\)

因此我们发现,想知道位置 \(i\) 的奇偶性,本质上就是通过我们的直接或间接询问得到 \(i-1\)\(i\) 的前缀和之间的关系。

我们把 \(0\)\(n\) 前缀和看做 \(n+1\) 个点,问题就转化为了求这些点的最小生成树。

套上模板就行啦。

#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
long long ans;
const int N = 2021;
struct bian
{
	int x,y,z;
	friend bool operator <(const bian &a,const bian &b){return a.z < b.z;}
}b[N * N / 2];
int fa[N];
int find(int x){return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);}
void he(int x,int y){fa[find(x)] = fa[find(y)];}
void Kruskal()
{
	for(int i = 0;i <= n;++ i)fa[i] = i;
	sort(b + 1,b + 1 + m);
	for(int i = 1,k = 0;i <= m;++ i)
	{
		if(find(b[i].x) != find(b[i].y))
		{
			he(b[i].x ,b[i].y);
			++ k;ans += b[i].z;
		}
		if(k == n){cout<<ans;break;}
	}
}
int main()
{
	cin>>n;
	for(int i = 1,v;i <= n;++ i)
		for(int j = i;j <= n;++ j)
		{
			++ m;b[m].x = i - 1;b[m].y = j;
			scanf("%d",&b[m].z);	
		}
	Kruskal();
	return 0;
}
posted @ 2021-08-17 11:04  wljss  阅读(84)  评论(1编辑  收藏  举报