挺有趣的一道题。
显然,我们如果知道某个位置的奇偶性,我们就能知道某个位置是否有小球(题目说明一个位置最多只有一个小球)。
我们有两种方法可以知道位置 (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;
}