zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    悼念丹尼斯·里奇,那个给乔布斯提供肩膀的巨人(转载)
    c# 做成Windows服务
    Visual Studio 2010 新建完项目编译就出错
    C#调用Win32 的API函数User32.dll
    c# Remoting小例子
    backgroundworker使用 实现进度条ProgressBar
    winform最小化后隐藏到右下角,单击或双击后恢复
    关于Thread的实例
    c# 捕获的异常写到日志里
    C# delegate and event 规范写法
  • 原文地址:https://www.cnblogs.com/Penn000/p/7478734.html
Copyright © 2011-2022 走看看