并查集模板
https://www.qduoj.com/problem/586
Description Z学长课间时总是会玩一些小游戏休闲片刻。这天,Z学长找到了这样的一个小游戏:开始时有n个石子(编号从1—n)从左至右依次排开,每个石子各自带有一个权值。有两种操作: 1.将编号为x的石子所在的堆和它那堆右面的堆合并为一堆,记作 “ M x ”,若该堆右侧无其它堆则忽略此次操作; 2.询问编号为x的石子所在的堆中权值最小的石子的权值为多少,记作“ Q x ”; 刚开始时由于所给石子数量过少,所以Z学长仍能应对自如,但越往后的关卡中所给的石子数越来越多,Z学长渐觉力不从心,因此特来求助于聪明的你,聪明的你能否帮学长度过难关?
Input 第1行输入n,q(n<=105,q<=105),表示石子的个数与询问的次数; 第2行给出n个值c[1]~c[n],ci表示编号为i的石子的权值; 其余q行,每行给出题中所描述的两种操作中的一种操作。
Output 对于每个“ Q x ” 询问操作,在单独的一行给出该询问的答案。
Sample Input 1 6 4 1 1 2 3 5 8 Q 1 M 3 M 3 Q 5
Sample Output 1 1 2
解题思路:
以权值最少的那一堆作为根节点合并 从t开始到n-1,如果t到t+1在一个堆里就继续,如果不在一个堆里就合并并且跳出循环。
package main
import "fmt"
var pre = [100005]int{}
var c = [100005]int{}
func find(x int) int {
if pre[x] == x {
return pre[x]
} else {
pre[x] = find(pre[x])
return pre[x]
}
}
func join(a, b int) {
fa := find(a)
fb := find(b)
if fa != fb && c[fa] < c[fb] {
pre[fb] = fa
} else {
pre[fa] = fb
}
}
func main() {
var n, q int
fmt.Scan(&n, &q)
for i := 1; i <= n; i++ {
fmt.Scan(&c[i])
pre[i] = i
}
for i := 1; i <= q; i++ {
var str string
var t int
fmt.Scan(&str, &t)
fmt.Println(str, t)
if str[0] == 'M' {
for ; t <= n-1; t++ {
if find(t) != find(t+1) {
join(t, t+1)
break
}
}
} else {
fmt.Printf("%d\n", c[find(t)])
}
}
}