UVA 11987 并查集删点

并查集删点就是弄个id记录当前点的id,删除的时候将id设为新的id,忽略原来的id,当然还要注意去改变原来集合需要维护的性质比如元素个数等等。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n,m;
int fa[maxn],id[maxn];
int cnt[maxn];ll sum[maxn];
int op,u,v;

int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}

void Union(int u,int v)
{
    int x=find(id[u]),y=find(id[v]);
    if(x==y) return;
    fa[x]=y;
    cnt[y]+=cnt[x];
    sum[y]+=sum[x];
}

void Remove(int u)
{
    int x=find(id[u]);
    cnt[x]--;
    sum[x]-=u;
    id[u]=++n;
    fa[id[u]]=id[u];
    cnt[id[u]]=1;
    sum[id[u]]=u;
}

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n>>m){
        REP(i,1,n) fa[i]=i,id[i]=i,cnt[i]=1,sum[i]=i;
        REP(i,1,m){
            scanf("%d",&op);
            if(op==1) scanf("%d%d",&u,&v),Union(u,v);
            else if(op==2){
                scanf("%d%d",&u,&v);
                int x=find(id[u]),y=find(id[v]);
                if(x==y) continue;
                Remove(u);
                Union(u,v);
            }
            else{
                scanf("%d",&u);
                int x=find(id[u]);
                printf("%d %lld\n",cnt[x],sum[x]);
            }
        }
    }
    return 0;
}

这题的坑点在于第二个操作,把u放在u所在集合的时候直接忽略,而不是把u拿出来。

时间: 2024-10-14 07:19:10

UVA 11987 并查集删点的相关文章

UVa 11987 并查集 Almost Union-Find

原文戳这 与以往的并查集不同,这次需要一个删除操作.如果是叶子节点还好,直接修改父亲指针就好. 但是如果要是移动根节点,指向它的所有子节点也会跟着变化. 所以要增加一个永远不会被修改的虚拟根节点,这样就可以把一个点从集合中删除而不影响其它的点了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std

ZOJ 3261 - Connections in Galaxy War ,并查集删边

In order to strengthen the defense ability, many stars in galaxy allied together and built many bidirectional tunnels to exchange messages. However, when the Galaxy War began, some tunnels were destroyed by the monsters from another dimension. Then m

南阳1022--合纵连横 (并查集+删点)

合纵连横 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 乱世天下,诸侯割据.每个诸侯王都有一片自己的领土.但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法吞并那些实力弱的,让自己的领土面积不断扩大.而实力弱的诸侯王为了不让自己的领土被吞并,他会联合一些其他同样弱小的诸侯国,组成联盟(联盟不止一个),来共同抵抗那些强大的诸侯国. 强大的诸侯国为了瓦解这些联盟,派出了最优秀的间谍来离间他们,使一些诸侯国退出联盟.最开始,每个诸侯国是一个联盟. 有两种操作 1

HDU4496_D-City(并查集删边/逆向)

D-City Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 1315    Accepted Submission(s): 496 Problem Description Luxer is a really bad guy. He destroys everything he met. One day Luxer went to D-

hdu 3081 【二分匹配+并查集+删边||最大路+并查集+二分枚举】

Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2307    Accepted Submission(s): 792 Problem Description Presumably, you all have known the question of stable marriage match. A

UVa 10129 (并查集 + 欧拉路径) Play on Words

题意: 有n个由小写字母的单词,要求判断是否存在某种排列是的相邻的两个单词,前一个单词末字母与后一个单词首字母相同. 分析: 将单词的两个字母看做节点,则一个单词可以看做一条有向边.那么题中所求的排列就等价于该有向图中是否存在欧拉路径. 在判断之前,首先要确定这个图是连通的,代码中用并查集来实现. 回顾一下存在欧拉路径的条件,全都是偶点或者有且仅有两个奇点.我们用deg来记录每个点的度,出度为1,入度为-1. 程序中判断存在欧拉路径的条件就是:deg全为0 或者 有两个不为0的,其中一个为1一个

nyoj_1022:合纵连横(并查集删点)

http://acm.nyist.net/JudgeOnline/problem.php?pid=1022 只附代码好了 #include<bits/stdc++.h> using namespace std; const int N=200005; int a[N],b[N],vis[N]; int n,m,add,kase; void init() { for(int i=0;i<n;i++) a[i]=i,b[i]=i; add=n; memset(vis,0,sizeof(vis

ZOJ - 3261 Connections in Galaxy War(并查集删边)

https://cn.vjudge.net/problem/ZOJ-3261 题意 银河系各大星球之间有不同的能量值, 并且他们之间互相有通道连接起来,可以用来传递信息,这样一旦有星球被怪兽攻击,便可通过通道找到能量值最大的星球来帮忙.但是有一些通道被怪兽破坏了. 现在先给出原来的所有通道, 然后进行询问,询问有两种方式: destroy a b: 连接a,b的通道被怪兽破坏了 query a: 询问a能否通过通道找到救兵,只能找能量值比自己大的救兵. 分析 逆向思维,先离线存储所有的输入操作,

Connections in Galaxy War ZOJ - 3261 离线操作+逆序并查集 并查集删边

#include<iostream> #include<cstring> #include<stdio.h> #include<map> #include<vector> #define cle(a) memset(a,0,sizeof(a)) using namespace std; const int N=50000+10; int w[20100]; bool cmp(int a,int b){ return a>b; } int n