博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces633G(SummerTrainingDay06-I dfs序+线段树+bitset)
阅读量:4660 次
发布时间:2019-06-09

本文共 5558 字,大约阅读时间需要 18 分钟。

G. Yash And Trees

time limit per test:4 seconds
memory limit per test:512 megabytes
input:standard input
output:standard output

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:

  1. for given node v and integer value x, increase all ai in the subtree of node v by value x
  2. 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 
3 #include
4 #include
5 #include
6 #include
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
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
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<
>(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
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
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
ans = query(1, in[v], out[v]);150 printf("%d\n", (int)((ans&prime).count()));151 }152 }153 }154 155 return 0;156 }

 

转载于:https://www.cnblogs.com/Penn000/p/7478734.html

你可能感兴趣的文章
正点原子 精英版( 实验22 IIC实验 )Usmart 无效 出现不了函数清单
查看>>
杭电OJ1789、南阳OJ236(贪心法)解题报告
查看>>
用表格制作商品购买页面--(table)
查看>>
jQuery
查看>>
0807-JAVA学习细则
查看>>
对应的德鲁伊applicationContext.xml配置
查看>>
【转】Android NDK学习(3)使用Javah命令生成JNI头文件 .
查看>>
添加端口
查看>>
P1004 方格取数
查看>>
bzoj 1008
查看>>
团队项目成员和题目
查看>>
【poj3468】A Simple Problem with Integers
查看>>
Kafka-导入导出数据
查看>>
Typescript 学习笔记六:接口
查看>>
Linux系统安装、配置Mysql以及远程连接设置
查看>>
Delphi 中的哈希表: THashedStringList
查看>>
git submodule
查看>>
测试数据
查看>>
Hello world!
查看>>
【转贴】龙芯生态产品和解决方案巡展(第四篇)——存储
查看>>