[bzoj5293][Bjoi2018]求和【最近公共祖先】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=5293
【题解】
  大力 O(NK) O ( N ∗ K ) 预处理,然后每次询问时倍增求LCA。
  这能算省选题?
【代码】

# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    N       300100
# define    T       20
# define    K       50
using namespace std;
int read(){
    int tmp = 0, fh = 1; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') fh = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){tmp = tmp * 10 + ch - '0'; ch = getchar(); }
    return tmp * fh;
}
struct Node{
    int data, next;
}e[N * 2];
const int P = 998244353;
int head[N], place, dad[N][T + 1], f[N][K + 1], n, dep[N], m;
void build(int u, int v){
    e[++place].data = v; e[place].next = head[u]; head[u] = place;
}
void dfs(int x, int fa){
    dep[x] = dep[fa] + 1; dad[x][0] = fa;
    for (int ed = head[x]; ed != 0; ed = e[ed].next)
        if (e[ed].data != fa)
            dfs(e[ed].data, x); 
}
void pre(){
    for (int i = 1, j = 1; j * 2 <= n; i++, j *= 2)
        for (int k = 1; k <= n; k++)
            dad[k][i] = dad[dad[k][i - 1]][i - 1];
}
int lca(int u, int v){
    if (dep[u] > dep[v]) swap(u, v);
    for (int i = T; i >= 0; i--)
        if (dep[dad[v][i]] >= dep[u])
            v = dad[v][i];
    if (u == v) return u;
    for (int i = T; i >= 0; i--)
        if (dad[u][i] != dad[v][i])
            u = dad[u][i], v = dad[v][i];
    return dad[u][0];
}
int main(){
//  freopen("C.in", "r", stdin);
//  freopen(".out", "w", stdout);
    n = read();
    for (int i = 1; i < n; i++){
        int u = read(), v = read();
        build(u, v); build(v, u);
    }
    dep[0] = -1;
    dfs(1, 0);
    pre();
    for (int i = 0; i <= n; i++){
        f[i][0] = 1;
        for (int j = 1; j <= K; j++)
            f[i][j] = 1ll * f[i][j - 1] * i % P;
        if (i != 0){
        for (int j = 1; j <= K; j++)
            f[i][j] = (f[i][j] + f[i - 1][j]) % P;
        }
    }
    m = read();
    for (int i = 1; i <= m; i++){
        int u = read(), v = read(), k = read();
        int l = lca(u, v);
        ll num = 1ll * f[dep[u]][k] + f[dep[v]][k] - f[dep[l]][k];
        if (l != 1) num = num - f[dep[dad[l][0]]][k];
        num = (num % P + P) % P;
        printf("%lld\n", num);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值