P8998 [CEOI2022] Prize 题解

Description

这是一道交互题。

Tomislav 在睡梦中想到了一个问题:给定两棵大小为 NN 的树,树上的节点按 1N1\sim N 分别编号,树则分别编号为树 11,树 22,树有边权,但是边权被隐藏了起来。

Tomislav 需要向交互库提供一个大小为 KK 的编号的子集 SS,在选择了这个集合后,小 C 可以问 QQ 个格式为 (a,b)(a,b) 的问题,定义 dt(x,y)d_t(x,y) 表示树 tt 上节点 xx 与节点 yy 的距离,ltl_t 表示树 tt 上节点 aa 与节点 bb 的 LCA,交互库会依次回答 d1(l1,a),d1(l1,b),d2(l2,a),d2(l2,b)d_1(l_1,a),d_1(l_1,b),d_2(l_2,a),d_2(l_2,b)

紧接着交互库会询问 TT 个格式为 (p,q)(p,q) 的问题,其中 p,qSp,q\in S,Tomislav 必须依次回答 d1(p,q)d_1(p,q)d2(p,q)d_2(p,q)

可怜的 Tomislav 并不会做,请你帮帮他。

1N1061\le N\le 10^62Kmin(N,105)2\le K\le \min(N,10^5)1Tmin(K2,105)1\le T\le \min(K^2,10^5)

Solution

考虑对于一棵树和给定的 SS 集合怎么做。

显然我们需要通过 k1k-1 次询问得到 SS 的虚树上每条边的权值,这个可以转化为求出每个点到根的距离 disdis

于是可以用类似建虚树的过程,按照 dfs 序后询问 dfs 序相邻的数,询问出来后可以分别得到 (disu,dislca)(dis_u,dis_{lca})(disv,dislca)(dis_v,dis_{lca}) 的数量关系,由于虚树上最多 2k22k-2 条边,所以这样做可以得到虚树上的点的 disdis 的关系。

如果有两棵树的话两棵树的 dfs 序排序后不一定相同,上面那个做法就不行了。

考虑对于第一棵树选择 dfs 序上的前缀,由于这些点在第一棵树上构成连通块,所以按照第二棵树的 dfs 序排序后仍能询问出第一棵树的关系。

时间复杂度:O(NlogN+K+T)O(N\log N+K+T)

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
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 1e6 + 5;

int n, k, q, t, rt1, rt2;
int p1[kMaxN], p2[kMaxN], dfn1[kMaxN], dfn2[kMaxN], idx1[kMaxN], idx2[kMaxN];
int lg[kMaxN], st1[kMaxN][20], st2[kMaxN][20], id[kMaxN];
int dis1[kMaxN], dis2[kMaxN];
std::vector<int> G1[kMaxN], G2[kMaxN];
std::vector<std::pair<int, int>> T1[kMaxN], T2[kMaxN];

int get(int *dfn, int x, int y) { return dfn[x] < dfn[y] ? x : y; }

void dfs1(int u, int fa) {
static int cnt = 0;
st1[dfn1[u] = ++cnt][0] = fa, idx1[cnt] = u;
for (auto v : G1[u]) {
if (v == fa) continue;
dfs1(v, u);
}
}

void dfs2(int u, int fa) {
static int cnt = 0;
st2[dfn2[u] = ++cnt][0] = fa, idx2[cnt] = u;
for (auto v : G2[u]) {
if (v == fa) continue;
dfs2(v, u);
}
}

int LCA1(int x, int y) {
if (x == y) return x;
if (dfn1[x] > dfn1[y]) std::swap(x, y);
int k = lg[dfn1[y] - dfn1[x]];
return get(dfn1, st1[dfn1[x] + 1][k], st1[dfn1[y] - (1 << k) + 1][k]);
}

int LCA2(int x, int y) {
if (x == y) return x;
if (dfn2[x] > dfn2[y]) std::swap(x, y);
int k = lg[dfn2[y] - dfn2[x]];
return get(dfn2, st2[dfn2[x] + 1][k], st2[dfn2[y] - (1 << k) + 1][k]);
}

void dfs3(int u) {
static bool vis[kMaxN] = {0};
vis[u] = 1;
for (auto [v, w] : T1[u]) {
if (vis[v]) continue;
dis1[v] = dis1[u] + w;
dfs3(v);
}
}

void dfs4(int u) {
static bool vis[kMaxN] = {0};
vis[u] = 1;
for (auto [v, w] : T2[u]) {
if (vis[v]) continue;
dis2[v] = dis2[u] + w;
dfs4(v);
}
}

void prework() {
dfs1(rt1, 0), dfs2(rt2, 0);
lg[0] = -1;
for (int i = 1; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
for (int i = 1; i <= lg[n]; ++i) {
for (int j = 1; j <= n - (1 << i) + 1; ++j) {
st1[j][i] = get(dfn1, st1[j][i - 1], st1[j + (1 << (i - 1))][i - 1]);
st2[j][i] = get(dfn2, st2[j][i - 1], st2[j + (1 << (i - 1))][i - 1]);
}
}
}

void dickdreamer() {
std::cin >> n >> k >> q >> t;
for (int i = 1; i <= n; ++i) {
std::cin >> p1[i];
if (~p1[i]) G1[p1[i]].emplace_back(i), G1[i].emplace_back(p1[i]);
else rt1 = i;
}
for (int i = 1; i <= n; ++i) {
std::cin >> p2[i];
if (~p2[i]) G2[p2[i]].emplace_back(i), G2[i].emplace_back(p2[i]);
else rt2 = i;
}
prework();
for (int i = 1; i <= k; ++i) {
id[i] = idx1[i];
std::cout << id[i] << ' ';
}
std::cout << std::endl;
std::sort(id + 1, id + 1 + k, [&] (int x, int y) { return dfn2[x] < dfn2[y]; });
for (int i = 1; i < k; ++i)
std::cout << "? " << id[i] << ' ' << id[i + 1] << '\n';
std::cout << "!" << std::endl;
for (int i = 1; i < k; ++i) {
int x = id[i], y = id[i + 1], lca1 = LCA1(x, y), lca2 = LCA2(x, y);
int d1, d2, d3, d4;
std::cin >> d1 >> d2 >> d3 >> d4;
T1[lca1].emplace_back(x, d1), T1[x].emplace_back(lca1, -d1);
T1[lca1].emplace_back(y, d2), T1[y].emplace_back(lca1, -d2);
T2[lca2].emplace_back(x, d3), T2[x].emplace_back(lca2, -d3);
T2[lca2].emplace_back(y, d4), T2[y].emplace_back(lca2, -d4);
}
dfs3(id[1]), dfs4(id[1]);
std::vector<std::pair<int, int>> res;
for (int i = 1; i <= t; ++i) {
int x, y;
std::cin >> x >> y;
int lca1 = LCA1(x, y), lca2 = LCA2(x, y);
res.emplace_back(dis1[x] + dis1[y] - 2 * dis1[lca1], dis2[x] + dis2[y] - 2 * dis2[lca2]);
}
for (auto [x, y] : res) std::cout << x << ' ' << y << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

P8998 [CEOI2022] Prize 题解
https://sobaliuziao.github.io/2024/12/13/post/ab834af3.html
作者
Egg_laying_master
发布于
2024年12月13日
许可协议