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利用位运算来完成循环移动就行了。

 //2017-09-05
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bitset>
#define lson (id<<1)
#define rson ((id<<1)|1)
#define mid ((tree[id].l+tree[id].r)>>1)
using namespace std; const int N = ;
const int M = ;
int n, m;
int head[N], tot;
struct Edge{
int to, next;
}edge[N<<]; void init(){
tot = ;
memset(head, -, sizeof(head));
} void add_edge(int u, int v){
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} //dfn记录dfs序,in[u]~out[u]的区间表示以u为根的子树。
int in[N], out[N], idx, dfn[N];
void dfs(int u, int fa){
in[u] = ++idx;
dfn[idx] = u;
for(int i = head[u]; i != -; i = edge[i].next){
int v = edge[i].to;
if(v != fa)
dfs(v, u);
}
out[u] = idx;
} int arr[N];
bitset<M> prime;
bool is_prime(int x){
for(int i = ; i*i <= x; i++)
if(x%i == )return false;
return true;
} void init_prime(){
prime.reset();
for(int i = ; i < m; i++)
if(is_prime(i))
prime.set(i);
} struct Node{
int l, r, lazy;
bitset<M> value;//value记录该区间内%m的余数的集合
}tree[N<<]; void push_up(int id){
tree[id].value = tree[lson].value | tree[rson].value;
} //循环移位,即value集合的每个数都加上了x。
void cyclic_shift(int id, int x){
tree[id].value = (tree[id].value<<x) | (tree[id].value>>(m-x));
} void push_down(int id){
if(tree[id].lazy){
tree[lson].lazy += tree[id].lazy;
tree[lson].lazy %= m;
tree[rson].lazy += tree[id].lazy;
tree[rson].lazy %= m;
cyclic_shift(lson, tree[id].lazy);
cyclic_shift(rson, tree[id].lazy);
tree[id].lazy = ;
}
} void build(int id, int l, int r){
tree[id].l = l;
tree[id].r = r;
tree[id].lazy = ;
if(l == r){
tree[id].value.reset();
tree[id].value.set(arr[dfn[l]]%m);
return;
}
build(lson, l, mid);
build(rson, mid+, r);
push_up(id);
} void update(int id, int l, int r, int x){
if(l <= tree[id].l && tree[id].r <= r){
tree[id].lazy += x;
tree[id].lazy %= m;
cyclic_shift(id, x);
return;
}
push_down(id);
if(l <= mid)update(lson, l, r, x);
if(r > mid)update(rson, l, r, x);
push_up(id);
} bitset<M> query(int id, int l, int r){
if(l <= tree[id].l && tree[id].r <= r){
return tree[id].value;
}
push_down(id);
bitset<M> ans;
if(l <= mid) ans |= query(lson, l, r);
if(r > mid)ans |= query(rson, l, r);
return ans;
} int main()
{
//freopen("inputI.txt", "r", stdin);
while(scanf("%d%d", &n, &m) != EOF){
//由于循环移位会将1移除m的范围,所以每次只求[1,m)之间的素数。
init_prime();
for(int i = ; i <= n; i++)
scanf("%d", &arr[i]);
int u, v;
init();
for(int i = ; i < n; i++){
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
idx = ;
dfs(, );
build(, , n);
int q, t, x;
scanf("%d", &q);
while(q--){
scanf("%d%d", &t, &v);
if(t == ){
scanf("%d", &x);
update(, in[v], out[v], x%m);
}else if(t == ){
bitset<M> ans = query(, in[v], out[v]);
printf("%d\n", (int)((ans&prime).count()));
}
}
} return ;
}

Codeforces633G(SummerTrainingDay06-I dfs序+线段树+bitset)的更多相关文章

  1. DFS序+线段树+bitset CF 620E New Year Tree(圣诞树)

    题目链接 题意: 一棵以1为根的树,树上每个节点有颜色标记(<=60),有两种操作: 1. 可以把某个节点的子树的节点(包括本身)都改成某种颜色 2. 查询某个节点的子树上(包括本身)有多少个不 ...

  2. Manthan, Codefest 16 G. Yash And Trees dfs序+线段树+bitset

    G. Yash And Trees 题目连接: http://www.codeforces.com/contest/633/problem/G Description Yash loves playi ...

  3. codeforces 620E. New Year Tree dfs序+线段树+bitset

    题目链接 给一棵树, 每个节点有颜色, 两种操作, 一种是将一个节点的子树全都染色成c, 一种是查询一个节点的子树有多少个不同的颜色, c<=60. 每个节点一个bitset维护就可以. #in ...

  4. codeforces 633G. Yash And Trees dfs序+线段树+bitset

    题目链接 G. Yash And Trees time limit per test 4 seconds memory limit per test 512 megabytes input stand ...

  5. Educational Codeforces Round 6 E dfs序+线段树

    题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...

  6. 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] D ...

  7. Codeforces 343D Water Tree(DFS序 + 线段树)

    题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...

  8. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  9. POJ 3321 DFS序+线段树

    单点修改树中某个节点,查询子树的性质.DFS序 子树序列一定在父节点的DFS序列之内,所以可以用线段树维护. 1: /* 2: DFS序 +线段树 3: */ 4:   5: #include < ...

随机推荐

  1. AC1000纪念

  2. 阿里云RDS数据库备份文件恢复到本地数据库

    参考这里:https://help.aliyun.com/knowledge_detail/41817.html 第4.2步要多注释掉一些(应该根据实际报错来注释): [mysqld] innodb_ ...

  3. 09-03 Java 抽象类

    抽象类的特点 /* 抽象类的概述: 动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的. 我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类. 抽象类的 ...

  4. IDEA快捷键--与Eclipse快捷键的对比--IDEA快捷键设置成Eclipse默认快捷键

    部分内容转载于:http://blog.csdn.net/dc_726/article/details/9531281 IntelliJ Idea 常用快捷键列表 Ctrl+Alt+t 选择代码块 t ...

  5. Redis 缓存服务配置与使用

    缓存服务器Couchbase另外一种选择Redis documentation http://redis.io/documentation http://redis.cn/documentation. ...

  6. 详解C#委托和事件(二)

    一.当我们使用关键字delegate声明一个自定义委托类型时,实际上是声明了一个该名称的类类型,继承自抽象类System.MulticastDelegate,还包含实例方法Invoke.BeginIn ...

  7. j2ee高级开发技术课程第四周

    分析hello.java,在hello1项目中.下载链接:https://github.com/javaee/tutorial-examples/tree/master/web/jsf/hello1 ...

  8. linux查看系统的硬件信息【转】

    linux查看系统的硬件信息,并不像windows那么直观,这里我罗列了查看系统信息的实用命令,并做了分类,实例解说. cpu lscpu命令,查看的是cpu的统计信息. blue@blue-pc:~ ...

  9. JDK7与JDK8中HashMap的实现

    JDK7中的HashMap HashMap底层维护一个数组,数组中的每一项都是一个Entry transient Entry<K,V>[] table; 我们向 HashMap 中所放置的 ...

  10. BIO与NIO、AIO的区别(这个容易理解)

    转自:http://blog.csdn.net/skiof007/article/details/52873421 BIO与NIO.AIO的区别(这个容易理解) IO的方式通常分为几种,同步阻塞的BI ...