zoukankan      html  css  js  c++  java
  • LuoguP1196 [NOI2002]银河英雄传说 并查集

    传送门

    题意:每次把一个序列接到另一个序列的末尾,求某次操作之后两元素的距离。

    题解:集合问题一般采用并查集。注意到每个集合必定是一条链,于是对每个集合,维护链头(即集合的根节点),链尾,每个节点到其父节点的距离。查询操作同带权并查集,合并操作就把一条链的链头接到另一条链的链尾。
    需要注意的是,路径压缩的过程中,先记录该节点原来的父节点,递归完成后再用父节点的dis值更新该节点的dis值。否则会用根节点的dis值(0)更新该节点,造成错误。

    看了其他的题解发现可以直接记录该集合的size值来代替链尾的记录

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAXN = 30005;
    
    int fa[MAXN], dis[MAXN], tail[MAXN];
    
    int get(int t){
    	if(fa[t] != t){
    		int f = fa[t];
    		fa[t] = get(fa[t]);
    		dis[t] += dis[f];
    //		tail[fa[t]] = t;
    	}
    	return fa[t];
    }
    
    void merge(int a, int b){
    	int A = get(a), B = get(b);
    	if(A != B){
    		fa[A] = tail[B];
    		dis[A] = 1;
    		tail[B] = tail[A];
    	}
    }
    
    int found(int a, int b){
    	int A = get(a), B = get(b);
    	if(A != B) return -1;
    	int ret = dis[a] - dis[b];
    	if(ret < 0) ret = -ret;
    	ret -= 1;
    	return ret;
    }
    
    int main(){
    //	freopen("in.txt", "r", stdin);
    	for(int i = 1; i <= 30000; i++) fa[i] = i, tail[i] = i;
    	int T;
    	scanf("%d", &T);
    	for(int i = 1; i <= T; i++){
    		char ch; int a, b;
    		scanf("
    %c%d%d", &ch, &a, &b);
    		if(ch == 'M'){
    			merge(a, b);
    		}
    		else{
    			printf("%d
    ", found(a, b));
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    Redis3.0.1 Stable版本的集群部署(Mac)
    Maven的包依赖冲突可引发java.lang.IncompatibleClassChangeError错误
    Key/Value存储系统etcd的特性
    实时消息平台NSQ的特性
    StringIO函数
    对文件内容进行迭代
    基本文件方法
    打开文件
    正则表达式知识点汇总
    编译
  • 原文地址:https://www.cnblogs.com/asdf1229/p/13892120.html
Copyright © 2011-2022 走看看