更好的阅读体验 Press Here
忽然没有了改题的欲望,我已经是一条咸鱼了
单链
将其转化为图论模型
对于位置为
x
x
的点,向 ,
x+1
x
+
1
连边,表示能到达
x
x
的点能够花费 的代价通过
+1/−1
+
1
/
−
1
而转移到
x−1
x
−
1
,
x+1
x
+
1
同时向
x+a[x]+1
x
+
a
[
x
]
+
1
连边,表示能够花费
1
1
的代价直接连到 。
同时因为直接转移到
n
n
的边已经变成了转移到 ,同时代价
+1
+
1
, 在统计答案时需要
−1
−
1
。
而当
0−>1
0
−
>
1
时需要
1
1
的费用,所以刚好抵消,答案就是 。使用BFS求距离即可
同样,用这种方法提取出 n n 条链可以作为 算法
树
按照原来单链的做法,向 子树中
dep[i]=dep[j]+a[j]+1
d
e
p
[
i
]
=
d
e
p
[
j
]
+
a
[
j
]
+
1
的点连边
但是发现这样最多会有
n2
n
2
条边,所以需要优化
使用 BFS 序来进行优化
因为每次连的边应该是在 BFS 序列上连续的一段 所以每次访问的点我们可以将其合并,使其指向下一个点,直到指向最右侧为止
这样的话我们访问所有节点应该是
α(n)∗n
α
(
n
)
∗
n
的复杂度,可以接受
所以访问方法就出来了,其实并不需要真的建边,知道如何走合法就行
算法流程如下:
while(!q.empty()) {
x = q.front();
if(!vis[fa[x]]) q.push(fa[x]);
for(i = son[x])
if(!vis[i]) q.push(i);
for(i = L - > R in x)
if(!vis[bfs[i]]) q.push(bfs[i]);//bfs[i]指第bfs序为i的元素编号
merge(i , i + 1);
}
那么怎么求
L
L
, 呢?
利用 DFS 的性质即可求出子树中
L
L
, 在第
dep[x]+a[x]+1
d
e
p
[
x
]
+
a
[
x
]
+
1
层的相对位置,再加上前
dep[x]+a[x]
d
e
p
[
x
]
+
a
[
x
]
层的节点个数,即为
L
L
,
流程如下:
void DFS(int x) {
++ dep_num[dep[x]];
L[x] = dep_num[dep[x] + a[x] + 1] + 1;
for(i = son[x]) DFS(i);
R[x] = dep_num[dep[x] + a[x] + 1];
}
for(int i = 1 ; i <= n ; ++ i) {
L[i] += dep_num_sum[dep[i] + a[i]];
R[i] += dep_num_sum[dep[i] + a[i]];
}
详细代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
struct edge {int t , n;}e[N << 1];
int head[N] , tot;
int fa[N << 1];
int bfs[N << 1] , id[N << 1] , dep[N << 1] , dep_num[N] , L[N] , R[N] , cnt , dep_num_sum[N];
int dis[N << 1] , f[N << 1] , a[N];
int n , rt , qwe;
int read() {
int ans = 0 , flag = 1;
char ch = getchar();
while(ch > '9' || ch < '0') {if(ch == '-') flag = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {ans = ans * 10 + ch - '0'; ch = getchar();}
return ans * flag;
}
void addedge(int u , int v) {
++ tot;
e[tot].t = v;
e[tot].n = head[u];
head[u] = tot;
}
void BFS(int x) {
memset(bfs , -1 , sizeof(bfs));
memset(dep , 0 , sizeof(dep));
dep[x] = 1;
queue <int> q;
q.push(x);
while(!q.empty()) {
x = q.front(); q.pop();
bfs[++ cnt] = x;
f[cnt] = cnt;
for(int i = head[x] ; i ; i = e[i].n) {
if(!dep[e[i].t]) {
q.push(e[i].t);
dep[e[i].t] = dep[x] + 1;
}
}
}
}
void DFS(int x) {
++ dep_num[dep[x]];
if(x > n) return;
L[x] = dep_num[dep[x] + a[x] + 1] + 1;
for(int i = head[x] ; i ; i = e[i].n)
DFS(e[i].t);
R[x] = dep_num[dep[x] + a[x] + 1];
}
int find(int x) {return f[x] == x ? f[x] : f[x] = find(f[x]);}
int main() {
freopen("a.in" , "r" , stdin);
freopen("a.out" , "w" , stdout);
qwe = n = read();
for(int i = 1 ; i <= n ; ++ i) {
a[i] = read();
if(a[i] == -1) rt = i;
int m = read();
for(int j = 0 ; j < m ; ++ j) {
int x = read();
fa[x] = i;
addedge(i , x);
}
if(!m) {fa[++ qwe] = i; addedge(i , qwe);}
}
BFS(rt); DFS(rt);
f[cnt + 1] = cnt + 1;
for(int i = 1 ; i <= n ; ++ i)
dep_num_sum[i] = dep_num_sum[i - 1] + dep_num[i];
for(int i = 1 ; i <= n ; ++ i) {
L[i] += dep_num_sum[dep[i] + a[i]];
R[i] += dep_num_sum[dep[i] + a[i]];
}
queue <int> q;
for(int i = head[rt] ; i ; i = e[i].n) {q.push(e[i].t); dis[e[i].t] = 1;}
while(!q.empty()) {
int x = q.front(); q.pop();
if(fa[x] != rt) {
if(!dis[fa[x]]) {
dis[fa[x]] = dis[x] + 1;
q.push(fa[x]);
}
for(int i = head[x] ; i ; i = e[i].n) {
if(!dis[e[i].t]) {
dis[e[i].t] = dis[x] + 1;
if(x <= n) q.push(e[i].t);
}
}
}
for(int i = find(L[x]) ; i <= R[x] ; i = find(i)) {
if(!dis[bfs[i]]) {
dis[bfs[i]] = dis[x] + 1;
if(bfs[i] <= n) q.push(bfs[i]);
}
f[i] = i + 1;
}
}
sort(dis + n + 1 , dis + cnt + 1);
for(int i = n + 1 ; i <= cnt ; ++ i)
printf("%d\n" , dis[i] - 1);
return 0;
}