zoukankan      html  css  js  c++  java
  • 洛谷 [p1196] 银河英雄传说

    所谓带权并查集

    本题所求的不止是两个编号之间是否有关系,还要求两个编号之间有什么关系,这就要求我们维护多个数组,fa[]数组维护两个编号之间的连通性,dis[]维护编号为i的战舰到fa[i]之间的距离,num[]维护编号为i的战舰所在的那一列有多少战舰。

    find函数

    int find(int x){
        if(x!=fa[x]){
            int k=fa[x];
            fa[x]=find(fa[x]);
            dis[x]+=dis[k];
            num[x]=num[fa[x]];
        }
        return fa[x];
    }
    

    每次find的时候都更新num数组与dis数组

    合并函数

    void merge(int x,int y){
        int r1=find(x),r2=find(y);
        if(r1!=r2){
            fa[r1]=r2;
                    dis[r1]=dis[r2]+num[r2];
            num[r2]+=num[r1];
            num[r1]=num[r2];
        }
    }
    

    合并时由于是将i号战舰所在的那一列并到j号所在列的尾端,所以dis[r1]=dis[r2]+num[r2]。

    询问函数

    int query(int a,int b){
        int r1=find(a),r2=find(b);
        if(r1!=r2){
            return -1;
        }else {
            return abs(dis[a]-dis[b])-1;
        }
    }
    

    注意返回时要加一

    AC代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int MAXN=30005;
    int read(){
        int rv=0,fh=1;
        char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-') fh=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            rv=(rv<<1)+(rv<<3)+c-'0';
            c=getchar();
        }
        return rv*fh;
    }
    int fa[MAXN],dis[MAXN],t,num[MAXN];
    int find(int x){
        if(x!=fa[x]){
            int k=fa[x];
            fa[x]=find(fa[x]);
            dis[x]+=dis[k];
            num[x]=num[fa[x]];
        }
        return fa[x];
    }
    void merge(int x,int y){
        int r1=find(x),r2=find(y);
        if(r1!=r2){
            fa[r1]=r2;dis[r1]=dis[r2]+num[r2];
            num[r2]+=num[r1];
            num[r1]=num[r2];
        }
    }
    int query(int a,int b){
        int r1=find(a),r2=find(b);
        if(r1!=r2){
            return -1;
        }else {
            return abs(dis[a]-dis[b])-1;
        }
    }
    int main(){
        freopen("in.txt","r",stdin);
        t=read();
        for(int i=1;i<=MAXN;i++) {fa[i]=i;num[i]=1;}
        for(int i=1;i<=t;i++){
            char c;
            scanf(" %c ",&c);
            int a=read(),b=read();
            if(c=='M'){
                merge(a,b);
            }else {
                printf("%d
    ",query(a,b));
            }
        }
    
        fclose(stdin);
        return 0;
    }
    
  • 相关阅读:
    实现用户注册验证码
    自带的打印预览
    分页存储过程
    文章标题、内容、摘要的处理函数
    ASP常用函数收藏
    生活中的经典感人语句
    如何在某一数据库的所有表的所有列上搜索一个字符串?
    如何访问隐藏的列表 workflow history list
    Windows Server 2008下如果什么操作没能正常完成, 请尝试run as administrator
    Visual Studio Build Marcos
  • 原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/7868344.html
Copyright © 2011-2022 走看看