【并查集】【模拟】Codeforces 699D Fix a Tree

题目链接:

  http://codeforces.com/problemset/problem/699/D

题目大意:

  通过给定当前节点的父亲给你一棵有错的树,可能有多个根和环,输出改成正确的一棵树至少要修改几个节点的父亲和修改后所有点的父亲值

题目思路:

  【并查集】【模拟】

  用并查集把成环的归在一起(类似强连通分量),然后统计分量数并修改。

  第一个出现的当作根,其余的每一块连通分量都去掉一条边改为连接到根上。

 1 //
 2 //by coolxxx
 3 ////<bits/stdc++.h>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<string>
 7 #include<iomanip>
 8 #include<map>
 9 #include<memory.h>
10 #include<time.h>
11 #include<stdio.h>
12 #include<stdlib.h>
13 #include<string.h>
14 //#include<stdbool.h>
15 #include<math.h>
16 #define min(a,b) ((a)<(b)?(a):(b))
17 #define max(a,b) ((a)>(b)?(a):(b))
18 #define abs(a) ((a)>0?(a):(-(a)))
19 #define lowbit(a) (a&(-a))
20 #define sqr(a) ((a)*(a))
21 #define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
22 #define mem(a,b) memset(a,b,sizeof(a))
23 #define eps (1e-8)
24 #define J 10
25 #define MAX 0x7f7f7f7f
26 #define PI 3.14159265358979323
27 #define N 200004
28 using namespace std;
29 typedef long long LL;
30 int cas,cass;
31 int n,m,lll,ans;
32 int root;
33 int a[N],fa[N];
34 int zhao(int aa)
35 {
36     if(fa[aa]==0 || fa[aa]==aa)return aa;
37     return (fa[aa]=zhao(fa[aa]));
38 }
39 int main()
40 {
41     #ifndef ONLINE_JUDGE
42     freopen("1.txt","r",stdin);
43 //    freopen("2.txt","w",stdout);
44     #endif
45     int i,j,fx,fy;
46 //    for(scanf("%d",&cas);cas;cas--)
47 //    for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
48     while(~scanf("%d",&n))
49 //    while(~scanf("%d",&n))
50     {
51         mem(fa,0);ans=0;root=0;
52         for(i=1;i<=n;i++)
53         {
54             scanf("%d",&a[i]);
55             if(a[i]==i)root=i;
56             fx=zhao(a[i]);
57             fy=zhao(i);
58             if(fx!=fy)
59                 fa[fy]=fx;
60         }
61         for(i=1;i<=n;i++)
62         {
63             fa[i]=zhao(i);
64             if(fa[i]==i)
65             {
66                 if(!root)
67                 {
68                     ans++;
69                     root=i;
70                     a[i]=i;
71                 }
72                 else if(i!=root)
73                     ans++,a[i]=root;
74             }
75         }
76         printf("%d\n",ans);
77         for(i=1;i<=n;i++)
78             printf("%d ",a[i]);
79         puts("");
80     }
81     return 0;
82 }
83 /*
84 //
85
86 //
87 */

时间: 2024-10-18 02:39:44

【并查集】【模拟】Codeforces 699D Fix a Tree的相关文章

棋盘上的守卫 并查集模拟外向基环树

棋盘上的守卫 基环树就是n个点n条边的树,每个点的入度为1就是外向基环树因为这样的话这个图是往外扩张的,反之内向. 然后这个树自然就只且只有一个环. 题意:n行m列,要求选n个守卫守卫n个行,m个守卫守卫m个列,守卫不能重复,且每个守卫只能守卫行或列,每个守卫一个价值,求最小的代价. 思路:将关于点的图转化为关于边的图,构造一个图含有n+m个点表示n行和m列,题目给的图上的每个点的价值就可以代表点到点的边权了,可以想到如果要覆盖所有的点,就是满足条件的方案,这样的话这个图就是一个每个点都是入度为

CodeForces 698B Fix a Tree (并查集应用)

当时也是想到了并查集,但是有几个地方没有想清楚,所以就不知道怎么写了,比如说如何确定最优的问题.赛后看了一下别人的思路,才知道自己确实经验不足,思维也没跟上. 其实没有那么复杂,这个题目我们的操作只有三个 1.确定根节点.2.解环. 3连接子树. 如果题目中给出了一个或者多个根节点,我们任选一个即可,证明:假设有k个可行根节点,那么选择一个不动,改动k-1次,每种选择都是这样.但如果题目中没有可选根节点,就不可以随便去选了,首先明确这种情况一定存在了1个或者多个环,我们一定要从环中选取根节点,因

【搜索】【并查集】Codeforces 691D Swaps in Permutation

题目链接: http://codeforces.com/problemset/problem/691/D 题目大意: 给一个1到N的排列,M个操作(1<=N,M<=106),每个操作可以交换X Y位置上的数字,求可以得到的最大字典序的数列. 题目思路: [搜索][并查集] 这题可以用搜索或者并查集写,都能过. 把位置分成若干块,每一块里面的位置都是可以被这一块里另一个位置经过若干次调换的(类似强连通,位置可达). 然后把每一块位置里的 位置按从小到大排序,位置上的值按从大到小排序,依次填入位置

CodeForces 698B Fix a Tree

并查集,构造. 先看一下图的特殊性,按照这种输入方式,一个点的入度最多只有$1$,因此,问题不会特别复杂,画画图就能知道了. 如果给出的序列中已经存在$a[i]=i$,那么随便取一个$a[i]=i$的$i$作为$root$,剩下的每一条边$a[i] \to i$,可以用并查集来处理,如果发现某条边$a[i] \to i$加入前$a[i]$与$i$已经在同一集合中,说明再加$a[i] \to i$会导致成环,因此将$i$的$father$改成$root$即可,并将$i$与$root$合并. 如果给

(并查集)Codeforces 325 D-Reclamation

借用 链接 的题意和解法分析的图片. 对于这种环的形式,先用常用的手段复制一份在右边.每次加点的过程只要看加完之后能不能通过已有的格子联通,如果联通则显然已经形成了一个环.这里判断联通我采用的办法是,分别看两个点八个方向是否联通的无脑办法.想法很明确,但实现的过程中要注意一些细节,如列坐标<=0或>2*m的处理. 1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #inclu

hdu2860 并查集模拟

判断条件有点坑 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<queue> 7 #include<algorithm> 8 #include<map> 9 #include<iomanip> 10 #include<cli

Codeforces Round #396 (Div. 2) D题Mahmoud and a Dictionary(并查集)解题报告

Mahmoud wants to write a new dictionary that contains n words and relations between them. There are two types of relations: synonymy (i. e. the two words mean the same) and antonymy (i. e. the two words mean the opposite). From time to time he discov

Codeforces 755C:PolandBall and Forest(并查集)

http://codeforces.com/problemset/problem/755/C 题意:该图是类似于树,给出n个点,接下来p[i]表示在树上离 i 距离最远的 id 是p[i],如果距离相等则p[i]是 id 较小的点. 思路:一开始没什么想法,画几分钟图发现不到什么东西,后来想着 i 和 p[i] 有关系,那么就代表 i 和 p[i] 是属于同一棵树,那么不就是并查集了嘛.抱着试一试的心态搞了一下居然过了. 1 #include <cstdio> 2 #include <c

Educational Codeforces Round 14 D. Swaps in Permutation (并查集orDFS)

题目链接:http://codeforces.com/problemset/problem/691/D 给你n个数,各不相同,范围是1到n.然后是m行数a和b,表示下标为a的数和下标为b的数可以交换无数次.问你最后字典序最大的数列是什么. 将下面的a和b用并查集联系起来存到祖节点对应的数组中,然后从大到小排序数组,最后依次按照父节点的数组中的顺序输出. 也可以用dfs的方法解(略麻烦),形成一个环路的就在一个数组中... 1 //并查集 2 #include <bits/stdc++.h> 3