题目大意:
给你一棵树,根节点为1
有2种操作,第一种是给u节点所在的子树的所有节点的权值+x
第二种是询问,假设v是子树u中的节点,有多少种质数满足av = p + m·k
做法:维护子树信息显然dfs序,考虑用线段树维护一个区间内有哪些值
每个区间用一个bitset维护
这里有一个小技巧,bitset都+x然后%m,可以bt2[k]=(bt2[k]<<y)|(bt2[k]>>(m-y));
然后求出区间的bitset,和质数的bitset&一下,求1的个数即可
代码如下:
#include<bits/stdc++.h> #define N 500005 using namespace std;bool vis[N]; int n,m,Q,x,y,opt,tim1,kk,tot,head[N],a[N],dfn[N],sz[N],pr[N]; bitset<1005>bt1,bt2[N],bt3;int ee[N],reall[N]; struct Tree{int nxt,to;}e[N]; inline void link(int x,int y){e[++kk].nxt=head[x];e[kk].to=y;head[x]=kk;} inline void init(){ for (int i=2;i<m;i++){ if (!vis[i]) pr[++tot]=i; for (int j=1;j<=tot;j++){ if (i*pr[j]>=m) break; vis[i*pr[j]]=true; if (i%pr[j]==0) break; } } } void dfs(int u,int fa){ sz[u]=1;dfn[u]=++tim1;reall[tim1]=a[u]; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (v==fa) continue; dfs(v,u);sz[u]+=sz[v]; } } void build(int k,int l,int r){ if (l==r){bt2[k][reall[l]]=1;return;} int mid=(l+r)>>1; build(k*2,l,mid);build(k*2+1,mid+1,r); bt2[k]=bt2[k*2]|bt2[k*2+1]; } void update(int k,int y){y%=m;bt2[k]=(bt2[k]<<y)|(bt2[k]>>(m-y));} inline void pushdown(int k){ if (!ee[k]) return; ee[k*2]=(ee[k*2]+ee[k])%m; ee[k*2+1]=(ee[k*2+1]+ee[k])%m; update(k*2,ee[k]);update(k*2+1,ee[k]); ee[k]=0; } void add(int k,int l,int r,int x,int y,int z){ if (l!=r) pushdown(k); if (x<=l&&y>=r){update(k,z);ee[k]=(ee[k]+z)%m;return;} int mid=(l+r)>>1; if (y<=mid) add(k*2,l,mid,x,y,z); else if (x>mid) add(k*2+1,mid+1,r,x,y,z); else add(k*2,l,mid,x,mid,z),add(k*2+1,mid+1,r,mid+1,y,z); bt2[k]=bt2[k*2]|bt2[k*2+1]; } void query(int k,int l,int r,int x,int y){ if (l!=r) pushdown(k); if (x<=l&&y>=r){bt3=bt3|bt2[k];return;} int mid=(l+r)>>1; if (y<=mid) query(k*2,l,mid,x,y); else if (x>mid) query(k*2+1,mid+1,r,x,y); else query(k*2,l,mid,x,mid),query(k*2+1,mid+1,r,mid+1,y); } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]%=m; for (int i=1;i<n;i++){ scanf("%d%d",&x,&y); link(x,y);link(y,x); } init(); for (int j=1;j<=tot;j++) bt1[pr[j]]=1; //printf("%d\n",(int)bt1.count()); dfs(1,-1); //for (int i=1;i<=n;i++) printf("%d ",dfn[i]);puts(""); //for (int i=1;i<=n;i++) printf("%d ",reall[i]);puts(""); build(1,1,n); //if (bt2[7][5]) puts("Yes1"); /*if (bt2[3][5]) puts("Yes1");// if (bt2[3][1]) puts("Yes2"); if (bt2[2][7]) puts("YES1"); if (bt2[2][8]) puts("YES2"); if (bt2[2][0]) puts("YES3"); if (bt2[1][8]) puts("Yes1"); if (bt2[1][7]) puts("Yes2"); if (bt2[1][5]) puts("Yes3"); if (bt2[1][1]) puts("Yes4"); if (bt2[1][0]) puts("Yes5");*/ scanf("%d",&Q); while (Q--){ scanf("%d%d",&opt,&x); if (opt==1){ scanf("%d",&y);y%=m; if (y) add(1,1,n,dfn[x],dfn[x]+sz[x]-1,y); } else { /*if (bt2[1][0]) puts("Yes1"); if (bt2[1][9]) puts("Yes2"); if (bt2[1][7]) puts("Yes3"); if (bt2[1][3]) puts("Yes4"); if (bt2[1][2]) puts("Yes5");*/ bt3.reset(); query(1,1,n,dfn[x],dfn[x]+sz[x]-1); //printf("%d\n",(int)bt3.count()); bt3=bt3&bt1; printf("%d\n",(int)bt3.count()); } } return 0; }