• Codeforces633G(SummerTrainingDay06-I dfs序+线段树+bitset)


    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 <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 }
  • 相关阅读:
    HarmonyOS三方件开发指南(5)——Photoview组件
    【2021年1月20日公开课】 多设备共享涂鸦画板的鸿蒙实现方式
    看透Spring MVC源代码分析与实践
    这道面试题,90%的人都不会
    Java多线程编程核心技术
    Head First设计模式
    美团面试题:为什么能直接调用userMapper接口的方法?
    七周七并发模型
    框架VS架构,看两者异同
    京东技术解密
  • 原文地址:https://www.cnblogs.com/Penn000/p/7478734.html
Copyright © 2020-2023  润新知