G. Yash And Trees
Yash loves playing with trees and gets especially excited when they have something to do with prime numbers. On his 20th birthday he was granted with a rooted tree of n nodes to answer queries on. Hearing of prime numbers on trees, Yash gets too intoxicated with excitement and asks you to help out and answer queries on trees for him. Tree is rooted at node 1. Each node i has some value ai associated with it. Also, integer m is given.
There are queries of two types:
- for given node v and integer value x, increase all ai in the subtree of node v by value x
- for given node v, find the number of prime numbers p less than m, for which there exists a node u in the subtree of v and a non-negative integer value k, such that au = p + m·k.
Input
The first of the input contains two integers n and m (1 ≤ n ≤ 100 000, 1 ≤ m ≤ 1000) — the number of nodes in the tree and value m from the problem statement, respectively.
The second line consists of n integers ai (0 ≤ ai ≤ 109) — initial values of the nodes.
Then follow n - 1 lines that describe the tree. Each of them contains two integers ui and vi (1 ≤ ui, vi ≤ n) — indices of nodes connected by the i-th edge.
Next line contains a single integer q (1 ≤ q ≤ 100 000) — the number of queries to proceed.
Each of the last q lines is either 1 v x or 2 v (1 ≤ v ≤ n, 0 ≤ x ≤ 109), giving the query of the first or the second type, respectively. It's guaranteed that there will be at least one query of the second type.
Output
For each of the queries of the second type print the number of suitable prime numbers.
Examples
input
8 20
3 7 9 8 4 11 7 3
1 2
1 3
3 4
4 5
4 6
4 7
5 8
4
2 1
1 1 1
2 5
2 4
output
3
1
1
input
5 10
8 7 5 1 0
1 2
2 3
1 5
2 4
3
1 1 0
1 1 2
2 2
output
2
题意:给你一棵树,根节点为1
有2种操作,第一种是给u节点所在的子树的所有节点的权值+x
第二种是询问,假设v是子树u中的节点,有多少种质数满足av = p + m·k,其中p<m
思路:首先用DFS序,把树转换为线性问题,使用线段树维护区间
因为m<=1000,我们用bitset保存av%m的值
每次对子树增加权值的时候,只需要修改懒惰标记,来记录增加的大小
然后直接把bitset利用位运算来完成循环移动就行了。
1 //2017-09-05 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 #include <bitset> 7 #define lson (id<<1) 8 #define rson ((id<<1)|1) 9 #define mid ((tree[id].l+tree[id].r)>>1) 10 using namespace std; 11 12 const int N = 110000; 13 const int M = 1020; 14 int n, m; 15 int head[N], tot; 16 struct Edge{ 17 int to, next; 18 }edge[N<<2]; 19 20 void init(){ 21 tot = 0; 22 memset(head, -1, sizeof(head)); 23 } 24 25 void add_edge(int u, int v){ 26 edge[tot].to = v; 27 edge[tot].next = head[u]; 28 head[u] = tot++; 29 } 30 31 //dfn记录dfs序,in[u]~out[u]的区间表示以u为根的子树。 32 int in[N], out[N], idx, dfn[N]; 33 void dfs(int u, int fa){ 34 in[u] = ++idx; 35 dfn[idx] = u; 36 for(int i = head[u]; i != -1; i = edge[i].next){ 37 int v = edge[i].to; 38 if(v != fa) 39 dfs(v, u); 40 } 41 out[u] = idx; 42 } 43 44 int arr[N]; 45 bitset<M> prime; 46 bool is_prime(int x){ 47 for(int i = 2; i*i <= x; i++) 48 if(x%i == 0)return false; 49 return true; 50 } 51 52 void init_prime(){ 53 prime.reset(); 54 for(int i = 2; i < m; i++) 55 if(is_prime(i)) 56 prime.set(i); 57 } 58 59 struct Node{ 60 int l, r, lazy; 61 bitset<M> value;//value记录该区间内%m的余数的集合 62 }tree[N<<4]; 63 64 void push_up(int id){ 65 tree[id].value = tree[lson].value | tree[rson].value; 66 } 67 68 //循环移位,即value集合的每个数都加上了x。 69 void cyclic_shift(int id, int x){ 70 tree[id].value = (tree[id].value<<x) | (tree[id].value>>(m-x)); 71 } 72 73 void push_down(int id){ 74 if(tree[id].lazy){ 75 tree[lson].lazy += tree[id].lazy; 76 tree[lson].lazy %= m; 77 tree[rson].lazy += tree[id].lazy; 78 tree[rson].lazy %= m; 79 cyclic_shift(lson, tree[id].lazy); 80 cyclic_shift(rson, tree[id].lazy); 81 tree[id].lazy = 0; 82 } 83 } 84 85 void build(int id, int l, int r){ 86 tree[id].l = l; 87 tree[id].r = r; 88 tree[id].lazy = 0; 89 if(l == r){ 90 tree[id].value.reset(); 91 tree[id].value.set(arr[dfn[l]]%m); 92 return; 93 } 94 build(lson, l, mid); 95 build(rson, mid+1, r); 96 push_up(id); 97 } 98 99 void update(int id, int l, int r, int x){ 100 if(l <= tree[id].l && tree[id].r <= r){ 101 tree[id].lazy += x; 102 tree[id].lazy %= m; 103 cyclic_shift(id, x); 104 return; 105 } 106 push_down(id); 107 if(l <= mid)update(lson, l, r, x); 108 if(r > mid)update(rson, l, r, x); 109 push_up(id); 110 } 111 112 bitset<M> query(int id, int l, int r){ 113 if(l <= tree[id].l && tree[id].r <= r){ 114 return tree[id].value; 115 } 116 push_down(id); 117 bitset<M> ans; 118 if(l <= mid) ans |= query(lson, l, r); 119 if(r > mid)ans |= query(rson, l, r); 120 return ans; 121 } 122 123 int main() 124 { 125 //freopen("inputI.txt", "r", stdin); 126 while(scanf("%d%d", &n, &m) != EOF){ 127 //由于循环移位会将1移除m的范围,所以每次只求[1,m)之间的素数。 128 init_prime(); 129 for(int i = 1; i <= n; i++) 130 scanf("%d", &arr[i]); 131 int u, v; 132 init(); 133 for(int i = 1; i < n; i++){ 134 scanf("%d%d", &u, &v); 135 add_edge(u, v); 136 add_edge(v, u); 137 } 138 idx = 0; 139 dfs(1, 0); 140 build(1, 1, n); 141 int q, t, x; 142 scanf("%d", &q); 143 while(q--){ 144 scanf("%d%d", &t, &v); 145 if(t == 1){ 146 scanf("%d", &x); 147 update(1, in[v], out[v], x%m); 148 }else if(t == 2){ 149 bitset<M> ans = query(1, in[v], out[v]); 150 printf("%d ", (int)((ans&prime).count())); 151 } 152 } 153 } 154 155 return 0; 156 }