[PA2014]Kuglarz

Link


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);
}
posted @ 2021-01-29 11:56  Kreap  阅读(44)  评论(0编辑  收藏  举报