UVA 11987 Almost Union-Find (并查集+删边)

摘要:
开始为您提供n个集合,m个操作,以及初始集合:{1},{2},}3},…,{n}有三个操作:1xx1yy1:合并xx1和yy1的两个集合2xx1yy1:分离xx1元素并将其合并为yy1 3xx1:查询xx1集合的元素数量,以及元素的所有值的总和,然后查询集合。1是合并两个集合,3是记录两个权重。因为只需要祖先的权重值,所以“查找”操作不需要更新权重值。下一步是分离元素。这里我使用映射方法:启动每个元素

  开始给你n个集合,m种操作,初始集合:{1}, {2}, {3}, … , {n} 
操作有三种: 
1 xx1 yy1 : 合并xx1与yy1两个集合 
2 xx1 yy1 :将xx1元素分离出来合到yy1上 
3 xx1 :查询xx1集合的元素个数,和元素所有值总和

  并查集,1就是合并两个集合,3要记录两个权值。因为只要祖先的权值,所以Find操作不需要更新权值。 
  接着就是分离元素了,在这儿我使用映射的方法:开始每个元素都映射自己,接着要删除元素时,我不直接删除元素(因为删除的话可能影响很大),我把此位置映射到不可能出现过得的新的一个值,这样我们处理一下原来的集合,再使用新的值维护一下现在的集合就好了,因为以后我们只是看映射的值,所以虽然没有直接删除值,但是原来的值我们不用。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=1<<28;
const double Pi=acos(-1.0);
const int Mod=1e9+7;
const int Max=200010;
int fat[Max],num[Max];
ll ran[Max];
int mp[Max],tot;//下标映射数字 找新值的代替前面的
void Init(int n)
{
    for(int i=0;i<=n;i++)
    {
        fat[i]=i;
        ran[i]=(ll)i;
        num[i]=1;
        mp[i]=i;
    }
    tot=n+1;
    return;
}
int Find(int x)
{
    if(x==fat[x])
        return fat[x];
    return fat[x]=Find(fat[x]);
}
void Union(int x,int y,int typ)
{
    int prex=x;//注意保存原来的值
    x=mp[x],y=mp[y];//注意映射
    int x1=Find(x);
    int y1=Find(y);
    if(x1==y1)
    return;
    if(typ==1)
    {
    fat[x1]=y1;
    ran[y1]+=ran[x1];
    num[y1]+=num[x1];
    return;
    }
    mp[prex]=tot++;//删除原有,添加到新地方,注意mp

    fat[mp[prex]]=y1;
    num[mp[prex]]=1;
    ran[mp[prex]]=(ll)x;

    num[x1]--;
    ran[x1]-=(ll)prex;

    num[y1]++;
    ran[y1]+=(ll)prex;
    return;
}
int main()
{
    int n,m;
    int typ,xx1,yy1;
    while(~scanf("%d %d",&n,&m))
    {
        Init(n);
        for(int i=0;i<m;i++)
        {
            scanf("%d",&typ);
            if(typ==1)
            {
                scanf("%d %d",&xx1,&yy1);
                Union(xx1,yy1,1);
            }
            else if(typ==2)
            {
            scanf("%d %d",&xx1,&yy1);
            Union(xx1,yy1,2);
            }
            else
            {
                scanf("%d",&xx1);
                yy1=Find(mp[xx1]);
                printf("%d %lld
",num[yy1],ran[yy1]);
            }
        }
    }
    return 0;
}

免责声明:文章转载自《UVA 11987 Almost Union-Find (并查集+删边)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Flink1.13.2版本 Standalone 模式部署[置顶] UNIX常用命令下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

LCA(最近公共祖先)离线算法Tarjan+并查集

本文来自:http://www.cnblogs.com/Findxiaoxun/p/3428516.html 写得很好,一看就懂了。 在这里就复制了一份。 LCA问题: 给出一棵有根树T,对于任意两个结点u,v求出LCA(T, u, v),即离根最远的结点x,使得x同时是u和v的祖先。      把LCA问题看成询问式的:给出一系列询问,程序应当对每一个询...

1034 Head of a Gang (30 分)(图的遍历or并查集)

dfs #include<bits/stdc++.h> using namespace std; const int N=3000; int mp[N][N]; int weight[N]; int vis[N]; map<string,int>si; map<int,string>is; map<string...

[BZOJ4569] [Luogu 3295] [SCOI2016]萌萌哒(并查集+倍增)

[BZOJ4569] [Luogu 3295] [SCOI2016]萌萌哒(并查集+倍增) 题面 有一个n位的十进制数a(无前导0),给出m条限制,每条限制((l_1,r_1,l_2,r_2)(保证r_1-l_1=r_2-l_2))表示这个数的第([l_1,r_1])位与([l_2,r_2])位相同。问有多少个这样的数满足条件,答案取模(10^9+7),...

kuangbin专题 专题九 连通图 POJ 3694 Network

题目链接:https://vjudge.net/problem/POJ-3694 题目:给定一个连通图,求桥的个数,每次查询,加入一条边,问加入这条边后还有多少个桥。 思路:tarjan + 并查集 + lca(朴素) 先用tarjan缩点(成环缩点),并存下桥,把每个scc都存下一个源点(源点(boss):以这个点代表这个scc)。 用存下的桥,用并查集...

并查集(Disjoint Set)

参考书籍《算法竞赛入门到进阶》 并查集的经典例子有连通子图、最小生成树Kruskal算法和最近公共祖先(LCA)等 并查集操作的简单实现 1.初始化。定义数组int s[ ] 是以结点 i 为元素的并查集,在开始的时候还没有进行处理,所以每个点都属于独立的集,并以 i 的值表示他的集s[ i ],例如元素 1 的集s[ 1 ] = 1。 2.合并。加入第1...

基础树上问题 P5836 [USACO19DEC]Milk Visits S【并查集进行图的染色】

题目 https://www.luogu.com.cn/problem/P5836    分析 由于每个点的颜色选择范围都是两种,所以我们可以使用并查集来记录同一种颜色的连通块。 刚开始我的思路比较歪,只是单纯的考虑怎样能记录可以使朋友开心,后来想到可以考虑在怎样的情况下不能使朋友开心 具体看代码 代码 #include<iostream>...