Summer Training day6 codeforces633G 线段树、bitset

来源:互联网 发布:linux线程的优先级控制 编辑:程序博客网 时间:2024/06/05 00:23

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 203 7 9 8 4 11 7 31 21 33 44 54 64 75 842 11 1 12 52 4
output
311
input
5 108 7 5 1 01 22 31 52 431 1 01 1 22 2
output
2
题解:这是一道非常有意思的题目。先将树dfs序展开,那么每段连续的区间相当于一颗子树。

由于m<=1000所以我们可以对于每一段都将该段出现的数字存下来。用什么来存储呢?用一个大小为M的bitset就可以了。

然后区间合并就用bitset的or操作给区间加一个数x就相当于对当前区间的bitset做一个循环左移m位的操作。

我们要询问某个区间有多少个质数,只需要一开始将小于m的质数处理出来,生成一个bitset类型为prime,ans表示查询到区间的bitset

那么最后的答案就是(prime & ans).count()

代码:

#include <iostream>#include <cstdio>#include <bitset>#include <cstring>using namespace std;int n,m;const int MAXN = 2e5+7;int a[MAXN],b[MAXN];int head[MAXN];int cnt;const int M = 1005;struct edge{     int v;     int next;     int cost; }Es[MAXN<<1];  void init(){     cnt = 0;     memset(head,-1,sizeof(head)); }inline void add_edge(int i,int j,int cost){       Es[cnt].v = j;     Es[cnt].cost = cost;     Es[cnt].next = head[i];     head[i] = cnt++; }   struct segtree{bitset<M> val[MAXN<<2];int addmark[MAXN<<2];void pushup(int rt){val[rt] = val[rt*2] | val[rt*2 + 1]; }void left_rotate(int rt,int x){x %= m;val[rt] = (val[rt] << x ) | (val[rt] >> (m - x));}void pushdown(int rt){if(addmark[rt]){addmark[rt*2] += addmark[rt];addmark[rt*2+1] += addmark[rt];left_rotate(rt*2,addmark[rt]);left_rotate(rt*2 + 1,addmark[rt]);addmark[rt] = 0;}}void build(int rt,int l,int r){if(l == r){//val[l].reset();val[rt].set(b[l] % m);//cout<<"rt:"<<rt<<" bit:"<<val[rt]<<endl;return ;}int mid = (l + r) / 2;build(rt*2,l,mid);build(rt*2+1,mid+1,r);pushup(rt);//cout<<"rt:"<<rt<<" bit:"<<val[rt]<<endl;}void update(int rt,int l,int r,int ul,int ur,int addval){if(l > ur || r < ul) return ;if(ul <= l && r <= ur){left_rotate(rt,addval);addmark[rt] = (addmark[rt] + addval) % m;return ;}int mid = (l+r)/2;pushdown(rt);update(rt*2,l,mid,ul,ur,addval);update(rt*2+1,mid+1,r,ul,ur,addval);pushup(rt);}bitset<M> query(int rt,int l,int r,int ul,int ur){if(l > ur || r < ul) return bitset<M>(0);if(ul <= l && r <= ur){return val[rt];}pushdown(rt);int mid = (l+r)/2;bitset<M> a = query(rt*2,l,mid,ul,ur);bitset<M> b = query(rt*2+1,mid+1,r,ul,ur);return a | b;}};int IN[MAXN],OUT[MAXN];int index = 0;int dfs(int x,int fa){IN[x] = ++ index;for(int e = head[x];e != -1;e = Es[e].next){int v = Es[e].v;if(v != fa){dfs(v,x);}}OUT[x] = ++ index;}segtree seg;bitset<M> getprime(int x){bitset<M> bit;bit.reset();for(int i = 2;i < x;i++){int f = 1;for(int j = 2;j*j <= i;j++){if(i % j == 0){f = 0;break;}}if(f){bit.set(i);}}return bit;}int main(){init();scanf("%d%d",&n,&m);bitset<M> prime = getprime(m);for(int i = 1;i <= n;i++){scanf("%d",&a[i]);}for(int i = 1;i < n;i++){int a,b;scanf("%d%d",&a,&b);add_edge(a,b,1);add_edge(b,a,1);}dfs(1,0);for(int i = 1;i <= n;i++){b[IN[i]] = b[OUT[i]] = a[i];}seg.build(1,1,2*n);int q;scanf("%d",&q);for(int i = 0;i < q;i++){int op;scanf("%d",&op);if(op == 1){int v,x;scanf("%d%d",&v,&x);seg.update(1,1,2*n,IN[v],OUT[v],x % m);}else if(op == 2){int v;scanf("%d",&v);bitset<M> bit = seg.query(1,1,2*n,IN[v],OUT[v]);//cout<<"count:"<<bit<<endl;printf("%d\n",(bit & prime).count());}}return 0;}





原创粉丝点击