标签:sub 倍增 lca ott set iostream std ext src
这是一道树链剖分/树上差分/LCA的题目……
本来想打一遍树剖,但是被那强大的码量劝退了,于是我开始思考树上差分。
我们先把每个点深度的k次方打一个表,之后我们因为要做减法,所以我们令vali,k?表示i到1号点路径上点深度的k次方之和
然后问题来了,我们维护的是点权和,所以我们发现直接减的话会导致lca这个点没算,所以略微改一下公式,使lca这个点也被算一次
然后我们询问u,v,k的时候输出valu,k?+valv,k?−vallca(u,v)?−valfalca(u,v)??即可
问题就是如何找lca了,这个用倍增预处理,在倍增寻找即可。
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 }
标签:sub 倍增 lca ott set iostream std ext src
原文地址:https://www.cnblogs.com/shl-blog/p/10805370.html