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。
JZOJ 5930. 【NOIP2018模拟10.26】山花_第1张图片

Solution

  • 显然我们可以对于每个质因子分开考虑。

  • 离线算出每个质因子对询问的贡献,那么乘起来就得到每个询问的答案了。

  • 因为: 2 ∗ 3 ∗ 5 ∗ 7 ∗ 11 ∗ 13 ∗ 17 ∗ 19 = 9699690 < 1 0 7 2*3*5*7*11*13*17*19=9699690<10^7 235711131719=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=apk)。

  • 从左到右扫,那么对于一个询问,它前面的 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] if[j] 吗?

  • 我们设一个数组 p r e pre pre ,使得 p r e [ i ∗ f [ j ] ] = f [ j ] pre[i*f[j]]=f[j] pre[if[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
#include
#include
#include
#include
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];
vectorss[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>=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

你可能感兴趣的:(数论,树状数组,图论,线性筛法)