JZOJ 5930. 【NOIP2018模擬10.26】山花
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
-
顯然我們可以對於每個質因子分開考慮。
-
離線算出每個質因子對詢問的貢獻,那麼乘起來就得到每個詢問的答案了。
-
因為:
-
所以一個數不同的質因子個數最多為 ,近似於一個 。
-
那麼我們列舉一個質因子 ,考慮計算其貢獻的答案。
-
我們把含有 的 和詢問 都拿出來,按其中含有 的個數從小到大排序()。
-
從左到右掃,那麼對於一個詢問,它前面的 與自己做 gcd 時得到 的個數肯定小於自己。
-
相反的,後面的 與自己的 gcd 得到 的個數肯定大於等於自己。
-
於是我們算出前面 的和、加上後面 的個數乘上自己的 個數(記為 ),
-
就得到了關於這個詢問的貢獻,即乘上 。
-
我們如何統計哪些 能被計算進詢問呢?用dfs序呀!
-
在 點處打上+1標記,在 的 級祖先處打上-1標記,用樹狀陣列查詢一段區間即可。
-
開始時我們需要將每個 分解質因數,我們可以先線篩出 以內的質數。
-
這裡有個小技巧,篩的時候不是從 篩掉 嗎?
-
我們設一個數組 ,使得 ,那麼我們順著 就能將 分解了。
-
那麼時間複雜度為 。
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;
}