Description
给定一棵n个节点带点权的树,要求资瓷q次询问
格式为(x,d),即求出x子树内距离x不超过d的点的点权的lcm,对998244353取模
n
≤
1
0
5
,
  
a
i
≤
1
0
7
n\le10^5,\; a_i\le10^7
n≤105,ai≤107
Solution
之前做过序列上的离线做法,上树就有点懵了
很常见的套路吧,没想到有点可惜
先不管那个深度的条件
我们把一个数分解,对于一个质因子p,将
p
1
、
p
2
、
p
3
.
.
.
p^1、p^2、p^3...
p1、p2、p3...的权值设为p,相同的数字我们只算一次贡献,那么就能解决lcm的问题了
然后我们对于相同的数字维护一个资瓷插入的虚树,每次讨论一下相邻节点的lca除掉贡献就能做到单点修改区间查询了,这样只需要一棵线段树就能做
考虑加上深度的限制会发生什么变化,那么就是深度<=某个数的节点才会被统计,那么我们按照深度建可持久化线段树就可以了
unorderd_map好像会快很多啊,不知道比赛能不能用呢
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <unordered_map>
#include <set>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int MOD=998244353;
const int N=100005;
struct edge {int y,next;} e[N*2];
std:: unordered_map <int,int> map;
std:: set <int>:: iterator it;
std:: set <int> set[N*30];
int size[N],pos[N],dfn[N],dep[N],fa[N],bl[N];
int rec[21][N*2],lg[N*2],in[N];
int p[N*7],rt[N],id[N],mn[N*100],a[N];
int L[N*600],R[N*600],P[N*600];
int ls[N],edCnt,tot,chp;
bool np[N*100];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}
void pre(int n) {
rep(i,2,n) {
if (!np[i]) p[++p[0]]=i,mn[i]=i;
for (int j=1;1LL*i*p[j]<=n&&j<=p[0];++j) {
np[i*p[j]]=1; mn[i*p[j]]=p[j];
if (i%p[j]==0) break;
}
}
}
LL ksm(LL x,LL dep) {
LL res=1;
for (;dep;dep>>=1) {
(dep&1)?(res=res*x%MOD):0;
x=x*x%MOD;
}
return res;
}
void dfs(int x) {
rec[0][++chp]=x; in[x]=chp;
pos[x]=++pos[0]; dfn[pos[x]]=x;
size[x]=1;
for (int i=ls[x];i;i=e[i].next) {
if (e[i].y==fa[x]) continue;
dep[e[i].y]=dep[x]+1; fa[e[i].y]=x;
dfs(e[i].y); size[x]+=size[e[i].y];
rec[0][++chp]=x;
}
}
void modify(int &now,int pre,int tl,int tr,int x,LL v) {
now=++tot; L[tot]=L[pre],R[tot]=R[pre],P[tot]=P[pre];
P[now]=v*P[now]%MOD;
if (tl==tr) return ;
int mid=(tl+tr)>>1;
if (x<=mid) modify(L[now],L[pre],tl,mid,x,v);
else modify(R[now],R[pre],mid+1,tr,x,v);
}
LL query(int now,int tl,int tr,int l,int r) {
if (r<l||!now) return 1;
if (tl>=l&&tr<=r) return P[now];
int mid=(tl+tr)>>1; LL res=1;
if (l<=mid) res=res*query(L[now],tl,mid,l,r);
if (mid+1<=r) res=res*query(R[now],mid+1,tr,l,r);
return (res>=MOD)?(res%MOD):res;
}
int get_lca(int x,int y) {
x=in[x],y=in[y];
if (x>y) std:: swap(x,y);
int u=lg[y-x+1];
x=rec[u][x],y=rec[u][y-(1<<u)+1];
return dep[x]<dep[y]?x:y;
}
bool cmp(int x,int y) {
return dep[x]<dep[y];
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
pre(1e7); P[0]=1;
int opt=read(),n=read(),lxf=0;
rep(i,1,n) a[i]=read(),id[i]=i;
rep(i,2,n) add_edge(read(),read());
dfs(dep[1]=1);
rep(i,2,chp) lg[i]=lg[i>>1]+1;
rep(j,1,lg[chp]) {
rep(i,1,chp-(1<<j)+1) {
if (dep[rec[j-1][i]]>dep[rec[j-1][i+(1<<j-1)]]) {
rec[j][i]=rec[j-1][i+(1<<j-1)];
} else rec[j][i]=rec[j-1][i];
}
}
std:: sort(id+1,id+n+1,cmp);
rep(i,1,n) {
int x=id[i],d=dep[x];
rt[d]=rt[dep[id[i-1]]];
for (;a[x]>1;) {
int yqw=mn[a[x]],wjp=1;
LL inv=ksm(mn[a[x]],MOD-2);
while (a[x]%yqw==0&&(a[x]/=yqw)) {
wjp=wjp*yqw;
if (!map[wjp]) map[wjp]=++lxf;
int now=map[wjp],tx=0,ty=0;
set[now].insert(pos[x]);
it=set[now].find(pos[x]);
it++; if (it!=set[now].end()) tx=dfn[*it]; it--;
if (it!=set[now].begin()) it--,ty=dfn[*it],it++;
modify(rt[d],rt[d],1,n,pos[x],yqw);
if (tx) modify(rt[d],rt[d],1,n,pos[get_lca(x,tx)],inv);
if (ty) modify(rt[d],rt[d],1,n,pos[get_lca(x,ty)],inv);
if (tx&&ty) modify(rt[d],rt[d],1,n,pos[get_lca(tx,ty)],yqw);
}
}
}
rep(i,dep[id[n]]+1,n) rt[i]=rt[i-1];
LL lastans=0;
for (int T=read(),x,d;T--;) {
x=read()^(opt*lastans),d=read()^(opt*lastans);
d=std:: min(dep[x]+d,n);
printf("%lld\n", lastans=query(rt[d],1,n,pos[x],pos[x]+size[x]-1));
}
//while (1) int ggg=0;
return 0;
}