题面
输入样例1
5 3
5 4 3
6 6 3 4 6
1 2 2 4
7 4 5 7 7
1 1 3 2
输出样例1
1
输入样例2
10 3
10 9 8
8 9 9 2 7 9 0 0 7 4
1 1 2 4 3 4 2 4 7
7 7 2 3 4 5 6 1 5 3
1 1 3 1 2 4 7 3 5
输出样例2
2
题意
给定两颗树 a , b a,b a,b 及 k k k 个在树上的点,问存在多少种方案,使得删除这 k k k 个点其中的一个后,剩余的 k − 1 k-1 k−1 个点在 A A A 树上的 L C A LCA LCA 对应点权值大于在 B B B 树上的 L C A LCA LCA 对应点权值。
由于只能删除一个点,因此方案数仅存在于 [ 0 , k ] [0,k] [0,k] 区间内。考虑采用预处理 k k k 个点的前后缀 L C A LCA LCA 的方式,设 p [ i ] p[i] p[i] 表示前 i i i 个点的 L C A LCA LCA, s [ i ] s[i] s[i] 后 i i i 个点的 L C A LCA LCA ,暴力枚举删除每个点后,剩余 k − 1 k-1 k−1 个点的 L C A LCA LCA 即为 l c a ( p [ i − 1 ] , s [ k − i ] ) lca(p[i-1],s[k-i]) lca(p[i−1],s[k−i]) ,暴力对比即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
vector<int> ha[N], hb[N];
int pa[N], sa[N], pb[N], sb[N]; //前后缀lca点
int x[N], wa[N], wb[N];
int dfna[N], ida[N << 1][25], deepa[N], cnt, lg2a[N << 1];
int dfnb[N], idb[N << 1][25], deepb[N], lg2b[N << 1];
void dfsa(int u, int dep) {
deepa[u] = dep;
dfna[u] = ++cnt;
ida[cnt][0] = u;
for (auto v : ha[u]) {
dfsa(v, dep + 1);
ida[++cnt][0] = u;
}
}
void dfsb(int u, int dep) {
deepb[u] = dep;
dfnb[u] = ++cnt;
idb[cnt][0] = u;
for (auto v : hb[u]) {
dfsb(v, dep + 1);
idb[++cnt][0] = u;
}
}
void RMQa() {
for (int i = 2; i <= cnt; i++)
lg2a[i] = lg2a[i >> 1] + 1;
for (int j = 1; j <= 20; j++)
for (int i = 1; (i + (1 << j) - 1) <= cnt; i++) {
int l = i, r = i + (1 << (j - 1));
ida[i][j] = deepa[ida[l][j - 1]] < deepa[ida[r][j - 1]]
? ida[l][j - 1]
: ida[r][j - 1];
}
}
void RMQb() {
for (int i = 2; i <= cnt; i++)
lg2b[i] = lg2b[i >> 1] + 1;
for (int j = 1; j <= 20; j++)
for (int i = 1; (i + (1 << j) - 1) <= cnt; i++) {
int l = i, r = i + (1 << (j - 1));
idb[i][j] = deepb[idb[l][j - 1]] < deepb[idb[r][j - 1]]
? idb[l][j - 1]
: idb[r][j - 1];
}
}
int querya(int x, int y) {
int l = dfna[x], r = dfna[y];
if (l > r)
swap(l, r);
int k = lg2a[r - l + 1];
return deepa[ida[l][k]] < deepa[ida[r - (1 << k) + 1][k]]
? ida[l][k]
: ida[r - (1 << k) + 1][k];
}
int queryb(int x, int y) {
int l = dfnb[x], r = dfnb[y];
if (l > r)
swap(l, r);
int k = lg2b[r - l + 1];
return deepb[idb[l][k]] < deepb[idb[r - (1 << k) + 1][k]]
? idb[l][k]
: idb[r - (1 << k) + 1][k];
}
signed main() {
int n, k;
cin >> n >> k;
int m;
cnt = 0;
for (int i = 1; i <= k; i++)
cin >> x[i];
for (int i = 1; i <= n; i++)
cin >> wa[i];
for (int i = 2; i <= n; i++) {
cin >> m;
ha[m].push_back(i);
}
for (int i = 1; i <= n; i++)
cin >> wb[i];
for (int i = 2; i <= n; i++) {
cin >> m;
hb[m].push_back(i);
}
dfsa(1, 0);
cnt = 0;
dfsb(1, 0);
RMQa();
RMQb();
//处理a的前后缀
pa[1] = pb[1] = x[1];
sa[1] = sb[1] = x[k];
for (int i = 2; i <= k; i++) {
pa[i] = querya(pa[i - 1], x[i]);
}
for (int i = 2; i <= k; i++) {
sa[i] = querya(sa[i - 1], x[k - i + 1]);
}
// b
for (int i = 2; i <= k; i++) {
pb[i] = queryb(pb[i - 1], x[i]);
}
for (int i = 2; i <= k; i++) {
sb[i] = queryb(sb[i - 1], x[k - i + 1]);
}
// for (int i = 1; i <= k; i++) {
// cout << pa[i] << " " << pb[i] << " ";
// cout << sa[i] << " " << sb[i] << endl;
// }
int ans = 0;
int a, b;
for (int i = 1; i <= k; i++) {
if (i == 1) {//后k-1个
a = sa[k - 1];
b = sb[k - 1];
} else if (i == k) {//前k-1个
a = pa[k - 1];
b = pb[k - 1];
} else {
a = querya(pa[i - 1], sa[k - i]);
b = queryb(pb[i - 1], sb[k - i]);
}
a = wa[a];
b = wb[b];
if (a > b)
ans++;
}
cout << ans << endl;
return 0;
}