Description
Input
Output
Sample Input
0 5
4 6 3 2 7
1 2
1 3
3 4
3 5
2
1 2
3 0
Sample Output
84
3
Data Constraint
Hint
注意:输入格式第5行“正整数”改为“非负整数”
分析:
考虑序列上要怎么做。
因为要取模,所以不能有欧几里得求lcm,只能通过因数分解形式求。显然不用质数间互不干扰,考虑一个质数
p
p
p的贡献。
这个数的贡献就是区间内
p
p
p的幂次的最大值。
考虑这样一个问题,求区间内不同数的乘积(相同的数只算一次)。我们考虑这样一种方法,对于每个数 a [ i ] a[i] a[i],设 p r e pre pre为前一个 a [ i ] a[i] a[i]所在的位置,那么在 p r e pre pre处除以 a [ x ] a[x] a[x],在 i i i处乘 a [ x ] a[x] a[x],然后对 i i i进行可持久化。那么 t r e e [ r ] − t r e e [ l − 1 ] tree[r]-tree[l-1] tree[r]−tree[l−1]这棵线段树的区间 [ l , r ] [l,r] [l,r]的乘积就是 [ l , r ] [l,r] [l,r]的答案。这要做有一个好处,就是可以不用管 a [ i ] a[i] a[i]的插入顺序。
对于这一题来说,我们设对于一个有
p
k
p^k
pk这个因子的数,
p
1
p^1
p1,
p
2
p^2
p2,…,
p
k
p^k
pk看成在这个位置的不同的数,代价都看做
p
p
p。考虑区间内不同数的乘积,如果存在
p
a
p^a
pa,那么必定存在
p
1
p^1
p1~
p
a
p^a
pa,而我们只要是存在的幂次都会贡献一个
p
p
p。
显然存在的幂次就是
p
1
p^1
p1~
p
m
a
x
p^{max}
pmax,贡献显然就是
p
m
a
x
p^{max}
pmax。序列上就做完了。
然后就是上树。对于一个节点来说,设他的权值为 x x x, p r e pre pre就是他的祖先中第一个权值为 x x x的节点。因为不用管顺序,考虑先把这些点按 d f s dfs dfs序排序后依次插入。那么 p r e pre pre就是它与排序后的数列中它的前一位的 l c a lca lca。然后我们可以通过区间查询求出答案。
因为询问有深度限制,我们应该按深度插入,此时使用
s
e
t
set
set维护
d
f
s
dfs
dfs序即可。
显然一个数分解质因数后不超过
l
o
g
n
logn
logn个数,然后主席树插入和set都是
l
o
g
log
log的。
总复杂度是
O
(
n
∗
l
o
g
n
∗
l
o
g
V
)
O(n*logn*logV)
O(n∗logn∗logV)
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#define LL long long
const int N=1e5+7;
const int maxa=1e7+7;
const LL mod=998244353;
using namespace std;
int n,opt,T,nump,cnt,tot,x,y;
int p[maxa],low[maxa],a[N],b[N],id[N],ls[N],dep[N],dfn[N][2],f[N][20],root[N];
bool not_prime[maxa];
struct edge{
int y,next;
}g[N*2];
struct node{
int l,r;
LL data;
}t[N*550];
set <int> s[N];
map <int,int> h;
bool cmp(int a,int b)
{
return dep[a]<dep[b];
}
void getprime(int n)
{
for (int i=2;i<=n;i++)
{
if (!not_prime[i])
{
p[++nump]=i;
low[i]=i;
}
for (int j=1;j<=nump;j++)
{
if (i*p[j]>n) break;
not_prime[i*p[j]]=1;
low[i*p[j]]=p[j];
if (i%p[j]==0) break;
}
}
}
void add(int x,int y)
{
g[++cnt]=(edge){y,ls[x]};
ls[x]=cnt;
}
void dfs(int x,int fa)
{
f[x][0]=fa;
dep[x]=dep[fa]+1;
dfn[x][0]=dfn[x][1]=++cnt;
id[cnt]=x;
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if (y==fa) continue;
dfs(y,x);
dfn[x][1]=dfn[y][1];
}
}
int getlca(int x,int y)
{
if (dep[x]>dep[y]) swap(x,y);
int d=dep[y]-dep[x],k=19,t=1<<k;
while (d)
{
if (d>=t) d-=t,y=f[y][k];
t/=2,k--;
}
if (x==y) return x;
k=19;
while (k>=0)
{
if (f[x][k]!=f[y][k])
{
x=f[x][k];
y=f[y][k];
}
k--;
}
return f[x][0];
}
LL ksm(LL x,LL y)
{
if (y==1) return x;
LL c=ksm(x,y/2);
c=(c*c)%mod;
if (y&1) c=(c*x)%mod;
return c;
}
void ins(int &p,int q,int l,int r,int x,int k)
{
p=++cnt;
t[p].data=t[q].data*k%mod;
if (l==r) return;
int mid=(l+r)/2;
if (x<=mid) t[p].r=t[q].r,ins(t[p].l,t[q].l,l,mid,x,k);
else t[p].l=t[q].l,ins(t[p].r,t[q].r,mid+1,r,x,k);
}
LL query(int p,int l,int r,int x,int y)
{
if (!p) return 1;
if ((l==x) && (r==y)) return t[p].data;
int mid=(l+r)/2;
if (y<=mid) return query(t[p].l,l,mid,x,y);
else if (x>mid) return query(t[p].r,mid+1,r,x,y);
else return query(t[p].l,l,mid,x,mid)*query(t[p].r,mid+1,r,mid+1,y)%mod;
}
int main()
{
freopen("half.in","r",stdin);
freopen("half.out","w",stdout);
getprime(1e7);
scanf("%d%d",&opt,&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=i;
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
cnt=0;
dfs(1,n);
for (int j=1;j<20;j++)
{
for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
}
sort(b+1,b+n+1,cmp);
cnt=0;
t[0].data=1;
for (int i=1;i<=n;i++)
{
int x=b[i],d=dep[x];
root[d]=root[dep[b[i-1]]];
while (a[x]>1)
{
int nowp=low[a[x]],P=1;
int inv=(int)ksm((LL)nowp,mod-2);
while (a[x]%nowp==0)
{
P*=nowp;
int c=h[P],last=0,next=0;
if (!c) c=++tot,h[P]=c;
s[c].insert(dfn[x][0]);
set <int> ::iterator it=s[c].lower_bound(dfn[x][0]);
if (it!=s[c].begin())
{
it--;
last=id[*it];
it++;
}
it++;
if (it!=s[c].end()) next=id[*it];
it--;
ins(root[d],root[d],1,n,dfn[x][0],nowp);
if (last) ins(root[d],root[d],1,n,dfn[getlca(last,x)][0],inv);
if (next) ins(root[d],root[d],1,n,dfn[getlca(x,next)][0],inv);
if ((last) && (next)) ins(root[d],root[d],1,n,dfn[getlca(last,next)][0],nowp);
a[x]/=nowp;
}
}
}
LL ans;
scanf("%d",&T);
for (int i=1;i<=T;i++)
{
scanf("%d%d",&x,&y);
x^=(int)ans*opt;
y^=(int)ans*opt;
y=min(dep[x]+y,dep[b[n]]);
ans=query(root[y],1,n,dfn[x][0],dfn[x][1]);
printf("%lld\n",ans);
}
}