Descriptionn

[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_#define


强制在线

[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_i++_02

Solution

之前好像做过一道叫七彩树的题,是这题的弱化版。

先考虑lcm,它实际上是每一个质因子的出现的指数取最大值然后乘积。

这里我们有一个很妙的转化。

考虑一个数[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_i++_03,它含有某一个因子[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_线段树_04,其中p为质数。
我们将[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_#define_05的每一个指数看做一个颜色,也就是说这个点有[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_可持久化线段树_06k种颜色,这k种颜色的权值都是p。

那么问题就转化为求查询范围内的所有点的出现过的颜色的权值积

考虑题目要求的点的限制,实际上就是[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_数据结构_07序在[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_i++_08,且深度小于[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_可持久化线段树_09的所有点。

我们可以将所有点按照深度排序,将深度从小到大插入点,用一棵对于深度可持久化的线段树来维护DFS序,预先算好答案,这样就能在每个询问的时候直接在可持久化线段树上找了。

维护树上每一种颜色只算一次的和或者乘积有一个很经典的套路,我们将颜色相同的点拉出来,按照DFS序排序,在每个点打上+标记,在相邻点的lca处打上-标记。

加上深度限制也是类似的,我们用一个set来维护同种颜色的DFS序大小关系。
考虑加入一个颜色为c的点u的影响,它会修改它与它的前驱和后继的lca处的标记,直接在当前深度的线段树上改答案即可。

分析复杂度,至多有[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_可持久化线段树_10种颜色,每种颜色的插入和修改都是一个log的
时间复杂度[JZOJ6086]【GDOI2019模拟2019.3.26】动态半平面交【数据结构】_数据结构_11

Code

#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 100005
#define M 200005
#define LL long long
#define mo 998244353
using namespace std;

int pi[11*N],ap[N][10][2],fs[N],nt[2*N],dt[2*N],n,q,l,m1,fr[100*N],le[N],dep[N],dfn[N],sz[N],fa[20][N];
LL pr[N];
bool bz[100*N];
void link(int x,int y)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
}

void prp()
{
int r=1e7;
fo(i,2,r)
{
if(!bz[i]) pi[++pi[0]]=i,fr[i]=i;
for(int j=1;j<=pi[0]&&i*pi[j]<=r;j++)
{
bz[i*pi[j]]=1,fr[i*pi[j]]=pi[j];
if(i%pi[j]==0) break;
}
}
}

void dfs(int k)
{
dfn[k]=++dfn[0];
sz[k]=1;
dep[k]=dep[fa[0][k]]+1;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=fa[0][k]) fa[0][p]=k,dfs(p),sz[k]+=sz[p];
}
}

LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
return s;
}

int lca(int x,int y)
{
if(dep[x]>dep[y]) swap(x,y);
for(int j=dep[y]-dep[x],c=0;j;c++,j>>=1) if(j&1) y=fa[c][y];
for(int j=19;x!=y;)
{
while(j&&fa[j][x]==fa[j][y]) j--;
x=fa[j][x],y=fa[j][y];
}
return x;
}

int d[N];
bool cmp(int x,int y)
{
return(dep[x]<dep[y]);
}
struct node
{
int x,d;
friend bool operator <(node x,node y){return x.d<y.d;}
};

set<node> bp[100*N];
typedef set<node>::iterator IT;

//segment tree
int rt[N],t[100*M][2],n1;
LL sv[100*M];

int opx,opy;
void nwp(int &x) {if(!x) x=++n1,sv[x]=1;}
void ins(int k,int l,int r)
{
if(l==r) sv[k]=sv[k]*(LL)opy%mo;
else
{
int mid=(l+r)>>1;
if(opx<=mid) nwp(t[k][0]),ins(t[k][0],l,mid);
else nwp(t[k][1]),ins(t[k][1],mid+1,r);
sv[k]=sv[t[k][0]]*sv[t[k][1]]%mo;
}
}
void merge(int &k,int x,int l,int r)
{
if(!k) {k=x;return;}
if(!x) return;
if(l==r) {sv[k]=sv[k]*sv[x]%mo;return;}
int mid=(l+r)>>1;
merge(t[k][0],t[x][0],l,mid),merge(t[k][1],t[x][1],mid+1,r);
sv[k]=sv[t[k][0]]*sv[t[k][1]]%mo;
}

LL query(int k,int l,int r)
{
if(opx>opy||opx>r||opy<l) return 1;
if(opx<=l&&r<=opy) return sv[k];
int mid=(l+r)>>1;
return query(t[k][0],l,mid)*query(t[k][1],mid+1,r)%mo;
}

int main()
{
cin>>l>>n;
fo(i,1,n) scanf("%lld",&pr[i]);
fo(i,1,n-1)
{
int x,y;
scanf("%d%d",&x,&y);
link(x,y),link(y,x);
}
prp();

fo(i,1,n)
{
d[0]=0;
int k=pr[i];
while(k>1) d[++d[0]]=fr[k],k/=fr[k];
sort(d+1,d+d[0]+1);
fo(j,1,d[0])
{
if(j==1||d[j]!=d[j-1]) le[i]++,ap[i][le[i]][0]=d[j];
ap[i][le[i]][1]++;
}
}

dfs(1);

fo(j,1,19) fo(i,1,n) fa[j][i]=fa[j-1][fa[j-1][i]];
fo(i,1,n) d[i]=i;
sort(d+1,d+n+1,cmp);
sv[0]=1;
for(int i=1,j=1;j<=n;i++)
{
rt[i]=++n1;
while(j<=n&&dep[d[j]]<=i)
{
int k=d[j];
fo(p1,1,le[k])
{
int p=ap[k][p1][0],v=p;
LL np=ksm(p,mo-2);
fo(q,1,ap[k][p1][1])
{
bp[v].insert((node){k,dfn[k]});
IT lf=bp[v].begin(),ri=bp[v].end(),w=bp[v].find((node){k,dfn[k]});
ri--;
opx=dfn[k],opy=p,ins(rt[i],1,n);
if((*w).x==(*lf).x)
{
if((*w).x!=(*ri).x)
{
ri=w,ri++;
opx=dfn[lca(k,(*ri).x)],opy=np,ins(rt[i],1,n);
}
}
else
{
lf=w,lf--;
opx=dfn[lca(k,(*lf).x)],opy=np,ins(rt[i],1,n);
if((*w).x!=(*ri).x)
{
ri=w,ri++;
opx=dfn[lca(k,(*ri).x)],opy=np,ins(rt[i],1,n);
opx=dfn[lca((*lf).x,(*ri).x)],opy=p,ins(rt[i],1,n);
}
}
v*=p;
}
}
j++;
}
merge(rt[i],rt[i-1],1,n);
}
cin>>q;

LL ans=0;
fo(i,1,q)
{
int x,u;
scanf("%d%d",&x,&u);
if(l) x^=ans,u^=ans;
opx=dfn[x],opy=dfn[x]+sz[x]-1;
printf("%lld\n",ans=query(rt[min(dep[d[n]],dep[x]+u)],1,n));
}
}