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