AT_abc267_f [ABC267F] Exactly K Steps

大家好,我是毒瘤,喜欢用玄学算法过题。

发现题解区没有这个做法,于是来发一篇。

思路

不难发现如果一个点对 (u,v)(u,v) 的距离为 dd,那么在这棵树以 uu 为根时,vv 的深度为 dd。于是考虑换根 DP。

首先思考如何计算答案。显然我们可以将查询离线下来,然后当换根到以 uu 为根时,将有关 uu 的所有查询全部解决即可。

其次,发现当一个 vv 转化成根时,它会在其父节点 uu 为根时的形态的基础上,所在 vv 子树中的节点深度减 11,其余节点加 11

然而,我们需要求的是深度为 dd 的节点,于是单单想大多数的换根 DP 维护深度的极值是不行的,所以需要更新出所有的深度。

于是这个东西需要使用数据结构维护。明确这个数据结构所需的功能:

  1. 区间加减。
  2. 区间查询权值为 kk 的编号。

于是你就想到了这道题。即用分块实现,一个 vector 维护块内的元素,每一次每一次修改都需要一次排序,查询都需要一次二分,单次操作是 Θ(nlogn)\Theta(\sqrt n \log \sqrt n) 的。配合上巨大常数,你得到了 TLE 15 的代码。

然后你可以发现此题是维护深度,所以值域很小,所以可以开桶维护。你在查询的时候每次都先看一下在这块中有没有出现 kk,如果出现了就直接暴力找;否则就继续向前面的块判断。这样实现即可单次操作做到 Θ(n)\Theta(\sqrt n)

于是你就得到了理论时间复杂度为 Θ(qn)\Theta(q \sqrt n) 的代码,但是常数有点小大,但是发现每一次的桶都不需要清空完,只需将原本的 valval 删掉,然后加上新的 valval 即可。

Code

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <bits/stdc++.h>  
#define fst first
#define snd second
#define re register

using namespace std;

typedef pair<int,int> pii;
const int N = 2e5 + 10,M = 4e5 + 10,K = 1010;
int n,q;
int idx,h[N],ne[M],e[M],ans[N];
int num,id[N],pid[N],sz[N],d[N],val[N];
vector<pii> Q[N];

inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}

inline void add(int a,int b){
ne[idx] = h[a];
e[idx] = b;
h[a] = idx++;
}

struct block{
int len,num;
int pos[N],L[K],R[K],tag[K],vis[K][N];

inline void init(){
len = num = sqrt(n);
for (re int i = 1;i <= n;i++) val[id[i]] = d[i];
for (re int i = 1;i <= num;i++){
L[i] = (i - 1) * len + 1;
R[i] = i * len;
}
if (R[num] != n){
num++;
L[num] = (num - 1) * len + 1;
R[num] = n;
}
for (re int i = 1;i <= num;i++){
for (re int j = L[i];j <= R[i];j++){
pos[j] = i;
vis[i][val[j]]++;
}
}
}

inline void modify(int l,int r,int k){
int p = pos[l],q = pos[r];
if (p == q){
for (re int i = l;i <= r;i++){
vis[p][val[i]]--;
val[i] += k;
vis[p][val[i]]++;
}
}
else{
for (re int i = l;i <= R[p];i++){
vis[p][val[i]]--;
val[i] += k;
vis[p][val[i]]++;
}
for (re int i = p + 1;i < q;i++) tag[i] += k;
for (re int i = L[q];i <= r;i++){
vis[q][val[i]]--;
val[i] += k;
vis[q][val[i]]++;
}
}
}

inline int query(int l,int r,int k){
int p = pos[l],q = pos[r];
if (p == q){
for (re int i = l;i <= r;i++){
if (val[i] + tag[p] == k) return pid[i];
}
}
else{
for (re int i = l;i <= R[p];i++){
if (val[i] + tag[p] == k) return pid[i];
}
for (re int i = p + 1;i < q;i++){
if (vis[i][k - tag[i]]){
for (re int j = L[i];j <= R[i];j++){
if (val[j] + tag[i] == k) return pid[j];
}
}
}
for (re int i = L[q];i <= r;i++){
if (val[i] + tag[q] == k) return pid[i];
}
}
return -1;
}
}bl;

inline void calc(int u){
for (auto x:Q[u]) ans[x.snd] = bl.query(1,n,x.fst + 1);
}

inline void dfs1(int u,int fa){
num++;
sz[u] = 1;
id[u] = num;
pid[num] = u;
d[u] = d[fa] + 1;
for (re int i = h[u];~i;i = ne[i]){
int j = e[i];
if (j == fa) continue;
dfs1(j,u);
sz[u] += sz[j];
}
}

inline void dfs2(int u,int fa){
for (re int i = h[u];~i;i = ne[i]){
int j = e[i];
if (j == fa) continue;
bl.modify(1,n,1);
bl.modify(id[j],id[j] + sz[j] - 1,-2);
calc(j);
dfs2(j,u);
bl.modify(1,n,-1);
bl.modify(id[j],id[j] + sz[j] - 1,2);
}
}

int main(){
memset(h,-1,sizeof(h));
n = read();
for (re int i = 1;i < n;i++){
int a,b;
a = read();
b = read();
add(a,b);
add(b,a);
}
q = read();
for (re int i = 1;i <= q;i++){
int a,b;
a = read();
b = read();
Q[a].push_back({b,i});
}
for (re int i = 1;i <= n;i++) sort(Q[i].begin(),Q[i].end());
dfs1(1,0);
bl.init();
calc(1);
dfs2(1,0);
for (re int i = 1;i <= q;i++) printf("%d\n",ans[i]);
return 0;
}

AT_abc267_f [ABC267F] Exactly K Steps
http://watersun.top/[题解]AT_abc267_f [ABC267F] Exactly K Steps/
作者
WaterSun
发布于
2024年6月12日
许可协议