[CF986E]Prince's Problem
Posted jefflyy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF986E]Prince's Problem相关的知识,希望对你有一定的参考价值。
题意:给一棵带点权$w_i$的树,多次询问$(u,v,x)$,求出$\prod\limits_{i\in\text{path}(u,v)}(w_i,x)$
因为是乘法,所以可以把路径询问拆成到根询问,这样就可以离线做了
因为求$\gcd$的本质是质因数指数取$\min$,所以在离线dfs时每到一个点就把它的点权质因数分解打上标记然后统计答案即可
具体地,对于$w_x=\prod\limits_{i=1}^kp_i^{a_i}$,我们把每个$p_i$的$1\cdots a_i$次幂乘上$p_i$的标记,统计答案时对$x=\prod\limits_{i=1}^kp_i^{a_i}$,对每个$p_i$都往答案乘上$[1,a_i]$的标记即可,dfs退栈时除回去以撤销
#include<stdio.h> #include<vector> using namespace std; typedef long long ll; const int mod=1000000007,T=10000000; int mul(int a,int b){return a*(ll)b%mod;} int pr[10000010],d[10000010],s[10000010]; int pow(int a,int b){ int s=1; while(b){ if(b&1)s=mul(s,a); a=mul(a,a); b>>=1; } return s; } void sieve(){ int i,j,M; M=0; d[1]=1; s[1]=1; for(i=2;i<=T;i++){ s[i]=1; if(d[i]==0){ M++; pr[M]=d[i]=i; } for(j=1;j<=M;j++){ if(pr[j]*(ll)i>T)break; d[i*pr[j]]=pr[j]; if(i%pr[j]==0)break; } } } int h[100010],nex[200010],to[200010],dep[100010],fa[100010][17],M; void add(int a,int b){ M++; to[M]=b; nex[M]=h[a]; h[a]=M; } void dfs(int x){ dep[x]=dep[fa[x][0]]+1; for(int i=h[x];i;i=nex[i]){ if(to[i]!=fa[x][0]){ fa[to[i]][0]=x; dfs(to[i]); } } } int lca(int x,int y){ int i; if(dep[x]<dep[y])swap(x,y); for(i=16;i>=0;i--){ if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; } if(x==y)return x; for(i=16;i>=0;i--){ if(fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; } } return fa[x][0]; } struct par{ int x,f; par(int a=0,int b=0){x=a;f=b;} }; vector<par>v[100010]; int a[100010],val[100010],ans[100010]; void solve(int x){ int i,j,t; for(i=a[x];i>1;){ for(j=t=d[i];i%t==0;i/=t,j*=t)s[j]=mul(s[j],t); } for(par p:v[x]){ for(i=val[p.x];i>1;){ for(j=t=d[i];i%t==0;i/=t,j*=t)ans[p.x]=mul(ans[p.x],p.f?s[j]:pow(s[j],mod-2)); } } for(i=h[x];i;i=nex[i]){ if(to[i]!=fa[x][0])solve(to[i]); } for(i=a[x];i>1;){ for(j=t=d[i];i%t==0;i/=t,j*=t)s[j]=mul(s[j],pow(t,mod-2)); } } int main(){ sieve(); int n,q,i,j,x,y; scanf("%d",&n); for(i=1;i<n;i++){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } for(i=1;i<=n;i++)scanf("%d",a+i); dfs(1); for(j=1;j<17;j++){ for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1]; } scanf("%d",&q); for(i=1;i<=q;i++){ scanf("%d%d%d",&x,&y,val+i); j=lca(x,y); v[x].push_back(par(i,1)); v[y].push_back(par(i,1)); v[j].push_back(par(i,0)); v[fa[j][0]].push_back(par(i,0)); ans[i]=1; } solve(1); for(i=1;i<=q;i++)printf("%d\n",ans[i]); }
以上是关于[CF986E]Prince's Problem的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces986E Prince's Problem 虚树可持久化线段树树状数组