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. Shell - 简明Shell入门10 - 管道(Pipe)

    示例脚本及注释 #!/bin/bash echo '##### Number of *.conf : ' find /etc -name *.conf | grep system | wc -l ec ...

  2. vue.js生命周期钩子函数及缓存

    在使用vue.js进行开发时,使用最多的就是created.mounted.activated. 由于有些情况下,我们需要复用某些组件,因此需要用到keep-alive. 当引入keep-alive时 ...

  3. django操作memcached

    1.首先需要在settings.py中配置好缓存 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.Me ...

  4. Wilcoxon-Mann-Whitney rank sum test

    Wilcoxon-Mann-Whitney ranksum test 无节点状况,假定为样本服从类似形状,如果不是类似形状的话,秩的比较没有过多意义. X有m个数,Y有n个数 \(H_0:\mu_1= ...

  5. How To Crop Bitmap For UWP

    裁剪图片主要是借助于 BitmapDecoder.GetPixelDataAsync() 以及 BitmapTransform对象来实现. 实现的代码如下: using System; using S ...

  6. git中多账号切换问题的解决方案(转)

    作者:知乎用户链接:https://www.zhihu.com/question/23028445/answer/416231632来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  7. 链表的反转、合并(不借助额外list数组)

    链表的基本操作:线性表 (单链表.循环链表-python实现) 反转链表: # -*- coding:utf-8 -*- class ListNode: def __init__(self, x): ...

  8. 使用node和express+mongodb实现数据增删改功能

    2018即将过去,2019即将来临,前端技术不断在在更新,学的东西越来越多.我们只有不断的学习,才不能被淘汰.在前后端分离的一个时代,后端提供接口,前端调用接口,逻辑判断,每个都是独立的工作.如果自己 ...

  9. Git 的4个阶段的撤销更改

    虽然git诞生距今已有12年之久,网上各种关于git的介绍文章数不胜数,但是依然有很多人(包括我自己在内)对于它的功能不能完全掌握.以下的介绍只是基于我个人对于git的理解,并且可能生编硬造了一些不完 ...

  10. logstash-3-输出到es中

    之前测试 filebeat和logstash的时候, 使用的是stdout标准输出, 现在我们想把数据输出到es中去, 1, 首先需要一个es: 修改配置文件 后台启动 ./bin/elasticse ...