[PA2014]Kuglarz
Solution
很巧妙的一道题……
如果想知道位置 \(i\) 是否有球,那就必须知道 \([i,i+1)\) 的奇偶性。反映在图上,就是点 \(i\) 和 \(i+1\) 必须是连通的,那么如果需要知道所有位置是否有球,那么 \(1\) 到 \(n+1\) 的所有点都必须连通。用边 \(u\to v\) 来表示询问区间 \([u,v)\),花费 \(c_{u,v-1}\)。跑最小生成树就求出了答案。
考虑这样做的正确性。如果 \(u\) 和 \(v\) 在图中是连通的,说明 \(u\) 和 \(v\) 之间有一条通路。这条通路上的每条边都表示一个询问 \([u_i,v_i)\)。容易知道,将这些询问的答案异或起来,其实就是区间 \([u,v)\) 的奇偶性。也就是说如果 \(u\) 和 \(v\) 连通,那它们之间的奇偶性就能知道了。那么最小生成树就是使得图连通的最小花费。
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 2007
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
struct E{
int u,v,dis;
bool operator<(const E &X)const{return dis<X.dis;}
}e[N*N];
int n,tot=0,fa[N],cnt;
inline int find(int x){
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
int main(){
n=cnt=read();
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
e[++tot]=(E){i,j+1,read()};
for(int i=1;i<=n+1;i++) fa[i]=i;
sort(e+1,e+1+tot);
long long ans=0;
for(int i=1;i<=tot;i++){
int u=e[i].u,v=e[i].v;
int fa_u=find(u),fa_v=find(v);
if(fa_u==fa_v) continue;
fa[fa_v]=fa_u;
ans+=1ll*e[i].dis;
if(!(--cnt)) break;
}
printf("%lld",ans);
}