“蔚来杯“2022牛客暑期多校训练营3 A-Ancestor(nlogn预处理LCA 暴力)

题面

在这里插入图片描述

输入样例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 ab k k k 个在树上的点,问存在多少种方案,使得删除这 k k k 个点其中的一个后,剩余的 k − 1 k-1 k1 个点在 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 k1 个点的 L C A LCA LCA 即为 l c a ( p [ i − 1 ] , s [ k − i ] ) lca(p[i-1],s[k-i]) lca(p[i1],s[ki]) ,暴力对比即可。

#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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值