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

合纵连横

时间限制:1000 ms  |  内存限制:65535 KB

难度:3

描述

乱世天下,诸侯割据。每个诸侯王都有一片自己的领土。但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法吞并那些实力弱的,让自己的领土面积不断扩大。而实力弱的诸侯王为了不让自己的领土被吞并,他会联合一些其他同样弱小的诸侯国,组成联盟(联盟不止一个),来共同抵抗那些强大的诸侯国。 强大的诸侯国为了瓦解这些联盟,派出了最优秀的间谍来离间他们,使一些诸侯国退出联盟。最开始,每个诸侯国是一个联盟。

有两种操作

1、U x y 表示x和y在同一个联盟。(0≤x,y<n)

2、D x   表示x退出联盟。

输入
多组测试数据
第一行两个数,n和m(1 ≤ n≤ 10^5, 1 ≤ m ≤10^5),分别表示诸侯国的个数和操作次数。
接下来有m行操作
输出
输出联盟的个数
样例输入
5 7
U 0 1
U 1 2
U 0 3
D 0
U 1 4
D 2
U 0 2
10 1
U 0 9
样例输出
Case #1: 2
Case #2: 9
上传者
ACM_马振阳
RE: 上午周赛出的这道题, 当时写了一半就发现不太对, 下午一看, 果然略坑;
并查集删点操作对于孩子节点来说, 直接father[i] = i;  就可以了。 根节点不能用这种方法,所以就建立一个新数组。
相当于把原来数组包含在里面一块进行操作, 根节点合并时 对新数组操作, 原来数组节点的删除也不会影响已经建立的关系。 删除的节点存为虚点,http://blog.csdn.net/a915800048/article/details/41703865

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 int father[100010], set[100010 * 2], vis[100010 * 2];
 6 int n, m;
 7 void init()
 8 {
 9     for(int i = 0; i < n; i++)
10     {
11         father[i] = i;
12         set[i] = i;
13     }
14 }
15 int find(int a)
16 {
17     int r, j, k;
18     r = a;
19     while(r != set[r])
20         r = set[r];
21     j = a;
22     while(j != r)
23     {
24         k = set[j];
25         set[j] = r;
26         j = k;
27     }
28     return r;
29 }
30 void mercy(int a, int b)
31 {
32     int q = find(a);
33     int p = find(b);
34     if(q != p)
35         set[q] = p;
36 }
37 int main()
38 {
39     int temp = 1;
40     while(~scanf("%d %d", &n, &m))
41     {
42         init();
43         int dis = n;  //虚点;
44         for(int i = 0; i < m; i++)
45         {
46             char str[2];
47             scanf("%s", str);
48             if(str[0] == ‘U‘)
49             {
50                 int a, b;
51                 scanf("%d %d", &a, &b);
52                 mercy(father[a], father[b]);
53             }
54             else
55             {
56                 int c;
57                 scanf("%d", &c);
58                 father[c] = dis;
59                 set[dis] = dis;
60                 dis++;
61             }
62         }
63         int ans = 0;
64         memset(vis, 0, sizeof(vis));
65         for(int i = 0; i < n; i++)
66         {
67                 if(!vis[find(father[i])])
68                 {
69                     //printf("%d %d %d\n", set[i], father[i], find(father[i]));
70                     vis[find(father[i])] = 1;
71                     ans++;
72                 }
73         }
74         printf("Case #%d: %d\n", temp++, ans);
75     }
76     return 0;
77 }

 
时间: 2024-08-07 14:45:14

南阳1022--合纵连横 (并查集+删点)的相关文章

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

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-

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) m

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

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

一笔画问题 南阳oj42 【并查集+欧拉通路的判断】

描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来. 规定,所有的边都只能画一次,不能重复画. 输入 第一行只有一个正整数N(N<=10)表示测试数据的组数. 每组测试数据的第一行有两个正整数P,Q(P<=1000,Q<=2000),分别表示这个画中有多少个顶点和多少条连线.(点的编号从1到P) 随后的Q行,每行有两个正整数A,B(0<A,B<P),表示编号为A和B的两点之间有连线. 输出 如果存在符合条件的连线

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

BZOJ 3319 黑白树 并查集+线段树

这这这这这这什么毒瘤题!!!!!!!!!!!!!!!!!!!!!!!!!!!! 卡LCT(优秀的LCT由于是均摊本身就带着2,3的常数在,而且这道题对于LCT标记十分难维护,又得乘上4,5然后就炸了),卡树剖,卡正解,但是暴力能A!!!!!!!!!!!!!!!!!!!!!! 所谓正解就是线段树为护dfs序+并查集删点去重,这东西在每个点一秒的时候都过不了Po姐都虚. 但是我在网上看到一个大佬有一个神思路A掉了 下面是我改过之后的的TLE程序 #include<cstdio> #include&