1. 程式人生 > >JZOJ 5930. 【NOIP2018模擬10.26】山花

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。 Data Constraint

Solution

  • 顯然我們可以對於每個質因子分開考慮。

  • 離線算出每個質因子對詢問的貢獻,那麼乘起來就得到每個詢問的答案了。

  • 因為:23571113

    1719=9699690<1072*3*5*7*11*13*17*19=9699690<10^7

  • 所以一個數不同的質因子個數最多為 88 ,近似於一個 loglog

  • 那麼我們列舉一個質因子 pp,考慮計算其貢獻的答案。

  • 我們把含有 ppaia_i 和詢問cc 都拿出來,按其中含有 pp 的個數從小到大排序(ai=apka_i=a*p^k)。

  • 從左到右掃,那麼對於一個詢問,它前面的 aia_i 與自己做 gcd 時得到 kk 的個數肯定小於自己。

  • 相反的,後面的 aia_i 與自己的 gcd 得到 kk 的個數肯定大於等於自己。

  • 於是我們算出前面 kk 的和、加上後面 aia_i 的個數乘上自己的 kk 個數(記為 sumsum),

  • 就得到了關於這個詢問的貢獻,即乘上 psump^{sum}

  • 我們如何統計哪些 aia_i 能被計算進詢問呢?用dfs序呀!

  • xx 點處打上+1標記,在 xxKK 級祖先處打上-1標記,用樹狀陣列查詢一段區間即可。

  • 開始時我們需要將每個 aia_i 分解質因數,我們可以先線篩出 10710^7 以內的質數。

  • 這裡有個小技巧,篩的時候不是從 ii 篩掉 if[j]i*f[j] 嗎?

  • 我們設一個數組 prepre ,使得 pre[if[j]]=f[j]pre[i*f[j]]=f[j] ,那麼我們順著 pre[ai]pre[a_i] 就能將 aia_i 分解了。

  • 那麼時間複雜度為 O(nlog2n)O(n\ log^2 n)

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;
}