Description
3.1 Background
春日的山中灌木茂盛,几乎长到了人的腰间,将山间都铺满了绿色。雨后的灌木之间还带着晨露,总会沾湿走过的行人的衣裳。
林中枝叶茂密,不过树木长的并不紧,遮不住天上,阳光落下照在山路上的灌木丛和落叶上。
山的另一侧,是漫山的花树,覆盖在山上,一直蔓延到山下,白瓣在微暖的阳光里透着粉红。风吹过,成片的花树摇动,花瓣翻飞而起,飘散开来,叫人移不开眼睛……
呵……这漫山的花树,叫小S怎能去雨露均沾呢……
3.2 Piece雨露均沾是不可能的,这辈子都不可能的,人力气又小,只能待到山花烂漫时,自取那满山烂漫来。3.3 Description今天又是去采花的好日子啊∼∼小S站在山顶,发现今日的花树们,在不甚平坦的山上,焕发出了别样的光彩。简单来说,它们组成了一棵以1为根的树(QuQ…每棵花树上有若干朵花,具体的,在编号为i的花树上有ai朵花。山花自然是越多越好,但小S却做不到雨露均沾…为了维护山间的生态多样性和自己的名誉和精力
小S决定从某一个节点u开始对其子树中与u距离小于K的节点代表的花树进行采摘。
特别的,节点u代表的花树也会被采摘。
依旧受限于精力,小S并不会亲自去采摘而是使用Extremely Strong的工具进行采摘。
我们定义一个工具的能力为c,小S会采摘的山树集合为T
那么小S能采摘到的山花数量fT = Πi∈T (ai
, c)
现在对于给定的树和阀值K,小S想要知道每一组询问的fT
Input
第一行,三个正整数n, Q, K,代表花树的棵数,询问次数和阀值。
接下来一行n个正整数,其中第i个数代表编号为i的花树的花的个数ai。
接下来n−1行,描述了花树们所形成的那棵树,每行两个正整数u, v,代表编号为u和v的花树直接相连。
接下来Q行,每行描述了一次询问,包含两个正整数x, c代表这次小S决定从编号为x的花树开始采摘,这次工具的能力为c。
Output
共Q行,每行一个整数ans,满足ans ≡ fi (mod 998244353)其中fi为第i次询问的答案,即能采摘到的山花数量
Sample Input
4 2 2
6 25 12 5
1 2
1 3
2 4
1 5
4 5
Sample Output
5
5
Data Constraint
Sample Inputx & Outputx
见选手下发文件中C_ex0.in/ans,C_ex1.in/ans。
Solution
-
显然我们可以对于每个质因子分开考虑。
-
离线算出每个质因子对询问的贡献,那么乘起来就得到每个询问的答案了。
-
因为: 2 ∗ 3 ∗ 5 ∗ 7 ∗ 11 ∗ 13 ∗ 17 ∗ 19 = 9699690 < 1 0 7 2*3*5*7*11*13*17*19=9699690<10^7 2∗3∗5∗7∗11∗13∗17∗19=9699690<107
-
所以一个数不同的质因子个数最多为 8 8 8 ,近似于一个 l o g log log。
-
那么我们枚举一个质因子 p p p,考虑计算其贡献的答案。
-
我们把含有 p p p 的 a i a_i ai 和询问 c c c 都拿出来,按其中含有 p p p 的个数从小到大排序( a i = a ∗ p k a_i=a*p^k ai=a∗pk)。
-
从左到右扫,那么对于一个询问,它前面的 a i a_i ai 与自己做 gcd 时得到 k k k 的个数肯定小于自己。
-
相反的,后面的 a i a_i ai 与自己的 gcd 得到 k k k 的个数肯定大于等于自己。
-
于是我们算出前面 k k k 的和、加上后面 a i a_i ai 的个数乘上自己的 k k k 个数(记为 s u m sum sum),
-
就得到了关于这个询问的贡献,即乘上 p s u m p^{sum} psum 。
-
我们如何统计哪些 a i a_i ai 能被计算进询问呢?用dfs序呀!
-
在 x x x 点处打上+1标记,在 x x x 的 K K K 级祖先处打上-1标记,用树状数组查询一段区间即可。
-
开始时我们需要将每个 a i a_i ai 分解质因数,我们可以先线筛出 1 0 7 10^7 107 以内的质数。
-
这里有个小技巧,筛的时候不是从 i i i 筛掉 i ∗ f [ j ] i*f[j] i∗f[j] 吗?
-
我们设一个数组 p r e pre pre ,使得 p r e [ i ∗ f [ j ] ] = f [ j ] pre[i*f[j]]=f[j] pre[i∗f[j]]=f[j] ,那么我们顺着 p r e [ a i ] pre[a_i] pre[ai] 就能将 a i a_i ai 分解了。
-
那么时间复杂度为 O ( n l o g 2 n ) O(n\ log^2 n) O(n log2n) 。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=1e5+5,M=1e7+5,mo=998244353;
struct data
{
int x,y,z;
}b[N<<1],c[N],t;
int n,q,k,tot;
int first[N],nex[N<<1],en[N<<1];
int a[N],f[N*7],pre[M],g[N*7];
int ans[N],dfn[N],size[N],fa[N],st[N],hl[N],hr[N],pos[M];
int vis[M],val[M];
bool bz[M];
vector<data>ss[N*7];
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
void write(int x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline void insert(int x,int y)
{
nex[++tot]=first[x];
first[x]=tot;
en[tot]=y;
}
void dfs(int x,int y,int z)
{
dfn[x]=++tot;
size[x]=1;
st[z]=x;
if(z>k) fa[x]=st[z-k];
for(int i=first[x];i;i=nex[i])
if(en[i]^y)
{
dfs(en[i],x,z+1);
size[x]+=size[en[i]];
}
}
inline bool cmp(data x,data y)
{
return x.y<y.y;
}
inline void changel(int x,int y)
{
while(x<=n) hl[x]+=y,x+=x&-x;
}
inline int findl(int x)
{
int sum=0;
while(x) sum+=hl[x],x-=x&-x;
return sum;
}
inline void changer(int x,int y)
{
while(x<=n) hr[x]+=y,x+=x&-x;
}
inline int findr(int x)
{
int sum=0;
while(x) sum+=hr[x],x-=x&-x;
return sum;
}
inline int ksm(int x,int y)
{
int s=1;
while(y)
{
if(y&1) s=(LL)s*x%mo;
x=(LL)x*x%mo;
y>>=1;
}
return s;
}
int main()
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
n=read(),q=read(),k=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
insert(x,y);
insert(y,x);
}
tot=0;
dfs(1,0,1);
for(int i=2;i<M;i++)
{
if(!bz[i]) f[++f[0]]=i;
for(int j=1;j<=f[0] && i*f[j]<M;j++)
{
bz[i*f[j]]=true;
pre[i*f[j]]=f[j];
if(i%f[j]==0) break;
}
}
for(int i=1;i<=q;i++)
{
c[i].x=read(),c[i].y=read(),c[i].z=i;
ans[i]=1;
}
memset(bz,false,sizeof(bz));
tot=0;
for(int i=1;i<=n;i++)
{
int x=a[i];
tot++;
st[0]=0;
while(pre[x])
{
if(vis[pre[x]]<tot)
{
vis[pre[x]]=tot;
st[++st[0]]=pre[x];
val[pre[x]]=0;
}
val[pre[x]]++;
if(!bz[pre[x]])
{
bz[pre[x]]=true;
g[++g[0]]=pre[x];
pos[pre[x]]=g[0];
}
x/=pre[x];
}
if(vis[x]<tot)
{
vis[x]=tot;
st[++st[0]]=x;
val[x]=0;
}
val[x]++;
if(!bz[x])
{
bz[x]=true;
g[++g[0]]=x;
pos[x]=g[0];
}
for(int j=1;j<=st[0];j++)
ss[pos[st[j]]].push_back((data){i,val[st[j]],0});
}
for(int i=1;i<=q;i++)
{
int x=c[i].y;
tot++;
st[0]=0;
while(pre[x])
{
if(vis[pre[x]]<tot)
{
vis[pre[x]]=tot;
st[++st[0]]=pre[x];
val[pre[x]]=0;
}
val[pre[x]]++;
x/=pre[x];
}
if(vis[x]<tot)
{
vis[x]=tot;
st[++st[0]]=x;
val[x]=0;
}
val[x]++;
for(int j=1;j<=st[0];j++) ss[pos[st[j]]].push_back((data){c[i].x,val[st[j]],i});
}
for(int p0=1;p0<=g[0];p0++)
{
int p=g[p0],cnt=tot=0;
for(int i=0;i<(int)ss[p0].size();i++)
{
b[++tot]=ss[p0][i];
if(b[tot].z) cnt++;
}
if(!cnt) continue;
sort(b+1,b+1+tot,cmp);
for(int i=1;i<=tot;i++)
if(!b[i].z)
{
changer(dfn[b[i].x],1);
if(fa[b[i].x]) changer(dfn[fa[b[i].x]],-1);
}
int sum1=0,sum2=0;
for(int i=1;i<=tot;i++)
if(!b[i].z)
{
changel(dfn[b[i].x],b[i].y);
changer(dfn[b[i].x],-1);
if(fa[b[i].x])
{
changel(dfn[fa[b[i].x]],-b[i].y);
changer(dfn[fa[b[i].x]],1);
}
}else
{
int sum1=findl(dfn[b[i].x]+size[b[i].x]-1)-findl(dfn[b[i].x]-1);
int sum2=findr(dfn[b[i].x]+size[b[i].x]-1)-findr(dfn[b[i].x]-1);
int sum=(sum1+(LL)sum2*b[i].y)%mo;
ans[b[i].z]=(LL)ans[b[i].z]*ksm(p,sum)%mo;
}
for(int i=1;i<=tot;i++)
if(!b[i].z)
{
changel(dfn[b[i].x],-b[i].y);
if(fa[b[i].x]) changel(dfn[fa[b[i].x]],b[i].y);
}
}
for(int i=1;i<=q;i++) write(ans[i]),putchar('\n');
return 0;
}