[BJOI2018]求和
先用倍增找出查询两点的
L
C
A
LCA
LCA,如果
L
C
A
LCA
LCA就是它们中的一个,那就直接在链上处理,注意
w
h
i
l
e
while
while它是怎么运行的,不要忘了加上最后LCA的贡献(做题的时候一定要想清楚再写,最好造几组特殊数据手玩)(要不是把题解扒了一篇下来对拍我估计还在
W
A
WA
WA)。如果
L
C
A
LCA
LCA不是它们中的一个,那就分别拆成两条链来处理,也注意如何计算
L
C
A
LCA
LCA的贡献。注意到
k
k
k很小,直接暴力计算即可(然而我还非常智障的去问神仙有没有公式来算这个
⋯
\cdots
⋯)
l u o g u luogu luogu上除了极限数据都 A C AC AC的代码(即直接暴力计算 k k k)
#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const ll Mod=998244353;
const int N=300000+50;
ll ans;
int tot,fir[N<<1],nxt[N<<1],to[N<<1],dep[N],f[25][N],n,m;
inline int read(){
int cnt=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-f;c=getchar();}
while(isdigit(c)){cnt=(cnt<<1)+(cnt<<3)+(c^48);c=getchar();}
return cnt*f;
}
inline ll ksm(int a,int b){
ll res=1LL;
while(b){if(b&1LL) res=res*(ll)a%Mod;a=a*a%Mod;b>>=1LL;}
return res%Mod;
}
inline void add(int x,int y){
nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;f[0][u]=fa;
for(int i=1;i<=20;++i) f[i][u]=f[i-1][f[i-1][u]];
for(int i=fir[u];i;i=nxt[i]){
int v=to[i];if(v==fa) continue;
dfs(v,u);
}return;
}
inline int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;--i) if(dep[f[i][x]]>=dep[y]) x=f[i][x];
if(x==y) return y;
for(int i=20;i>=0;--i)
if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
return f[0][x];
}
inline ll work1(int u,int v,int k){
ll res=0;
while(u!=v){
res=res+ksm(dep[u],k);
if(res>Mod) res-=Mod;
u=f[0][u];
}
res+=ksm(dep[v],k);
return res%Mod;
}
inline ll work2(int u,int v,int Lca,int k){
ll res=0;
while(u!=Lca){
res=res+ksm(dep[u],k);
if(res>Mod) res-=Mod;
u=f[0][u];
}
while(v!=Lca){
res=res+ksm(dep[v],k);
if(res>Mod) res-=Mod;
v=f[0][v];
}
res=res+ksm(dep[Lca],k);
if(res>Mod) res-=Mod;
return res%Mod;
}
inline ll del(int u,int v,int k){
if(dep[u]<dep[v]) swap(u,v);int Lca=LCA(u,v);
if(Lca==v) return work1(u,v,k);
else return work2(u,v,Lca,k);
}
signed main(){
n=read();int x,y;dep[0]=-1;
for(int i=1;i<n;++i) {x=read(),y=read();add(x,y);add(y,x);}dfs(1,0);
m=read();int i,j,k;
while(m--){
i=read(),j=read(),k=read();
ans=del(i,j,k)%Mod;
printf("%lld\n",ans);
}
return 0;
}
加上预处理后通过
h
a
c
k
hack
hack数据的代码
预处理即预处理深度的
k
k
k次方之和。
注意到我们预处理的过程,记
v
a
l
[
u
]
[
k
]
val[u][k]
val[u][k]为
u
u
u节点深度的
k
k
k次方,那么考虑计算的过程:
l
c
a
lca
lca及上面都被算了两次,但因为我们本来就要算一次
l
c
a
lca
lca的值,所以最后答案就是
v
a
l
[
u
]
[
k
]
+
v
a
l
[
v
]
[
k
]
−
v
a
l
[
l
c
a
]
[
k
]
−
v
a
l
[
f
a
[
l
c
a
]
]
[
k
]
val[u][k]+val[v][k]-val[lca][k]-val[fa[lca]][k]
val[u][k]+val[v][k]−val[lca][k]−val[fa[lca]][k]。
注意最后取模。
#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const ll Mod=998244353;
const int N=300000+50;
ll ans;
int tot,fir[N<<1],nxt[N<<1],to[N<<1],dep[N],f[25][N],n,m,power[N],val[N][55];
inline int read(){
int cnt=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-f;c=getchar();}
while(isdigit(c)){cnt=(cnt<<1)+(cnt<<3)+(c^48);c=getchar();}
return cnt*f;
}
inline ll ksm(int a,int b){
ll res=1LL;
while(b){if(b&1LL) res=res*(ll)a%Mod;a=a*a%Mod;b>>=1LL;}
return res%Mod;
}
inline void add(int x,int y){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;f[0][u]=fa;
for(int i=1;i<=20;++i) f[i][u]=f[i-1][f[i-1][u]];
for(int i=1;i<=50;++i) power[i]=power[i-1]*dep[u]%Mod;
for(int i=1;i<=50;++i) val[u][i]=(power[i]+val[fa][i])%Mod;
for(int i=fir[u];i;i=nxt[i]){
int v=to[i];if(v==fa) continue;
dfs(v,u);
}return;
}
inline int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;--i) if(dep[f[i][x]]>=dep[y]) x=f[i][x];
if(x==y) return y;
for(int i=20;i>=0;--i)
if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
return f[0][x];
}
signed main(){
freopen("data.in","r",stdin);
freopen("judge.out","w",stdout);
n=read();int x,y;dep[0]=-1;power[0]=1;
for(int i=1;i<n;++i) {x=read(),y=read();add(x,y);add(y,x);}dfs(1,0);
m=read();int i,j,k;
while(m--){
i=read(),j=read(),k=read();
int Lca=LCA(i,j);
int ans=(val[i][k]+val[j][k]+2*Mod-val[Lca][k]-val[f[0][Lca]][k])%Mod;
printf("%lld\n",ans);
}
return 0;
}