【BJOI2018】求和

这是一道树链剖分/树上差分/LCA的题目……

本来想打一遍树剖,但是被那强大的码量劝退了,于是我开始思考树上差分。

我们先把每个点深度的k次方打一个表,之后我们因为要做减法,所以我们令vali,k表示i到1号点路径上点深度的k次方之和

然后问题来了,我们维护的是点权和,所以我们发现直接减的话会导致lca这个点没算,所以略微改一下公式,使lca这个点也被算一次

然后我们询问u,v,k的时候输出valu,k​+valv,k​−vallca(u,v)−valfalca(u,v)即可

问题就是如何找lca了,这个用倍增预处理,在倍增寻找即可。

【BJOI2018】求和
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 inline int read() {
 8     int ret=0;
 9     int op=1;
10     char c=getchar();
11     while(c<'0'||c>'9') {if(c=='-') op=-1; c=getchar();}
12     while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
13     return ret*op;
14 }
15 const ll mod=998244353;
16 struct node {
17     int next,to;
18 }a[300010<<1];
19 int num,head[300010<<1];
20 int n,m;
21 int f[300010][25];
22 ll d[300010];
23 ll pow[60],val[300010][60];
24 inline void add(int from,int to) {
25     a[++num].next=head[from]; a[num].to=to;    head[from]=num;
26     swap(from,to);
27     a[++num].next=head[from]; a[num].to=to;    head[from]=num;
28 }
29 void dfs(int u,int fa) {
30     for(int i=0;f[u][i];i++) f[u][i+1]=f[f[u][i]][i];
31     for(int i=head[u];i;i=a[i].next) {
32         int v=a[i].to;
33         if(v==fa) continue ;
34         f[v][0]=u;
35         d[v]=d[u]+1;
36         for(int j=1;j<=50;j++) pow[j]=pow[j-1]*d[v]%mod;
37         for(int j=1;j<=50;j++) val[v][j]=(val[u][j]+pow[j])%mod;
38         dfs(v,u);
39     }
40 }
41 int lca(int x,int y) {
42     if(d[x]<d[y]) swap(x,y);
43     for(int i=20;i>=0;i--)
44         if(d[f[x][i]]>=d[y]) x=f[x][i];
45     if(x==y) return x;
46     for(int i=20;i>=0;i--)
47         if(f[x][i]!=f[y][i]) {
48             x=f[x][i];
49             y=f[y][i];
50         }
51     return f[x][0];
52 }
53 int main() {
54     n=read();
55     for(int i=1;i<n;i++) add(read(),read());
56     pow[0]=1;
57     dfs(1,0);
58     m=read();
59     while(m--) {
60         ll ans=0;
61         int i=read(),j=read(),k=read();
62         int xx=lca(i,j);
63         ans=val[i][k]+val[j][k]-val[xx][k]-val[f[xx][0]][k]+mod+mod;
64         printf("%lld\n",ans%mod);
65     }
66     return 0;
67 }
AC Code

 

上一篇:! BJOI2018链上二次求和


下一篇:如何判断大小端?(C语言实现)