Maze

题意概述

有$n$个排成一行的传送器,第$i$个传送器可以传送到$[L_i, R_i]$之间的所有传送器上(传送前的身影还在),可以多次传送。你现在随机出生在一个传送器上,求有你身影的传送器个数的期望。

算法分析

首先利用线段树优化建图,使得点数为$O(n)$,边数为$O(n\log n)$。

这是一张有向图。考虑在同一个强连通分量中的两个点,它们的答案一定是一样的。因此可以将图中的强连通分量缩成一个点,对每个强连通分量分别计算答案。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <cstdio>
#include <iomanip>
#include <cstring>
using namespace std;
struct node_type {
int l, r, child[2];
} node[300001];
struct edge {
int v, c, nxt;
} e[600001];
int n, tot, nume, id, h[300001], que[600001], dfn[300001], low[300001];
int top, sta[300001], cnt, belong[300001], pnt[300001];
long double ans;
bool vis[300001];
void add_edge(int u, int v) {
if (u == v) return;
e[++nume].v = v, e[nume].nxt = h[u], h[u] = nume;
}
void build_tree(int root) {
int mid = node[root].l + node[root].r >> 1;
if (node[root].l == mid) {
node[root].child[0] = mid, add_edge(root, mid);
} else {
node[++tot].l = node[root].l, node[tot].r = mid;
node[root].child[0] = tot, add_edge(root, tot), build_tree(tot);
}
if (mid + 1 == node[root].r) {
node[root].child[1] = mid + 1, add_edge(root, mid + 1);
} else {
node[++tot].l = mid + 1, node[tot].r = node[root].r;
node[root].child[1] = tot, add_edge(root, tot), build_tree(tot);
}
}
void insert_line(int root, int l, int r, int t) {
if (node[root].l == l && node[root].r == r) {
add_edge(t, root); return;
}
int mid = node[root].l + node[root].r >> 1;
if (r <= mid) insert_line(node[root].child[0], l, r, t);
else if (l > mid) insert_line(node[root].child[1], l, r, t);
else {
insert_line(node[root].child[0], l, mid, t);
insert_line(node[root].child[1], mid + 1, r, t);
}
}
void dfs(int t) {
dfn[t] = low[t] = ++id;
sta[++top] = t, vis[t] = true;
for (int i = h[t]; i; i = e[i].nxt) {
if (!dfn[e[i].v]) dfs(e[i].v), low[t] = min(low[t], low[e[i].v]);
else if (vis[e[i].v]) low[t] = min(low[t], dfn[e[i].v]);
}
if (dfn[t] == low[t]) {
int v; ++cnt;
do belong[v = sta[top--]] = cnt, vis[v] = false; while (v != t);
}
}
int bfs(int u) {
memset(vis, false, sizeof(vis));
int s = 0, t = 0, ret = 1;
vis[que[++t] = u] = true;
while (s < t) {
int v = que[++s];
for (int i = h[v]; i; i = e[i].nxt) {
if (!vis[e[i].v]) {
vis[que[++t] = e[i].v] = true;
if (e[i].v && e[i].v <= n) ++ret;
}
}
}
return ret;
}
int main()
{
scanf("%d", &n); tot = n + 1;
for (int i = 1; i <= n; ++i) node[i].l = node[i].r = i;
node[tot].l = 1, node[tot].r = n, build_tree(tot);
for (int i = 1; i <= n; ++i) {
int l, r;
scanf("%d%d", &l, &r);
insert_line(n + 1, l, r, i);
}
for (int i = 1; i <= tot; ++i) if (!dfn[i]) dfs(i);
for (int i = 1; i <= n; ++i) {
if (!pnt[belong[i]]) pnt[belong[i]] = bfs(i);
ans += pnt[belong[i]];
}
printf("%.6llf\n", ans / n);
return 0;
}

Maze
https://regmsif.cf/2017/07/12/oi/maze/
作者
RegMs If
发布于
2017年7月12日
许可协议