zoukankan      html  css  js  c++  java
  • 2017 ACM-ICPC, Universidad Nacional de Colombia Programming Contest K

    Tamref love random numbers, but he hates recurrent relations, Tamref thinks that mainstream random generators like the linear congruent generator suck. That's why he decided to invent his own random generator.

    As any reasonable competitive programmer, he loves trees. His generator starts with a tree with numbers on each node. To compute a new random number, he picks a rooted subtree and multiply the values of each node on the subtree. He also needs to compute the number of divisors of the generated number (because of cryptographical applications).

    In order to modify the tree (and hence create different numbers on the future), Tamref decided to perform another query: pick a node, and multiply its value by a given number.

    Given a initial tree T, where Tu corresponds to the value on the node u, the operations can be summarized as follows:

    • RAND: Given a node u compute and count its divisors, where T(u) is the set of nodes that belong to the subtree rooted at u.
    • SEED: Given a node u and a number x, multiply Tu by x.

    Tamref is quite busy trying to prove that his method indeed gives integers uniformly distributed, in the meantime, he wants to test his method with a set of queries, and check which numbers are generated. He wants you to write a program that given the tree, and some queries, prints the generated numbers and count its divisors.

    Tamref has told you that the largest prime factor of both Tu and x is at most the Tamref's favourite prime: 13. He also told you that the root of T is always node 0.

    The figure shows the sample test case. The numbers inside the squares are the values on each node of the tree. The subtree rooted at node 1 is colored. The RAND query for the subtree rooted at node 1 would generate 14400, which has 63 divisors.

    Input

    The first line is an integer n (1 ≤ n ≤ 105), the number of nodes in the tree T. Then there are n - 1 lines, each line contains two integers u and v (0 ≤ u, v < n) separated by a single space, it represents that u is a parent of v in T. The next line contains n integers, where the i - th integer corresponds to Ti (1 ≤ Ti ≤ 109). The next line contains a number Q (1 ≤ Q ≤ 105), the number of queries. The final Q lines contain a query per line, in the form "RAND u" or "SEED u x" (0 ≤ u < n, 1 ≤ x ≤ 109).

    Output

    For each RAND query, print one line with the generated number and its number of divisors separated by a space. As this number can be very long, the generated number and its divisors must be printed modulo 109 + 7.

    Example

    Input
    8
    0 1
    0 2
    1 3
    2 4
    2 5
    3 6
    3 7
    7 3 10 8 12 14 40 15
    3
    RAND 1
    SEED 1 13
    RAND 1
    Output
    14400 63
    187200 126

    题意:给一颗树共n个点,以及其结点的数值ai,有q次行为,查询询问子树(包括节点)的数值的积,与更新单个节点即乘题给数(一开始以为是整个子树都要更新)


    思路:明显的线段树题,但是问题是线段树里存的是什么。如果直接存积,数组开long long也存不下。那么就需要换种思路,存积的质因子的指数。

    即把积X=(p1^a)*(p2^b)*(p3^c)*······中的a,b,c用数组记录。又题目给出子树结点的积可以用不超过13的素数的积来表示。则定义一个b[]={2,3,5,7,11,13}。

    就能表示所有子树积。这样查询到以后可以直接用快速幂求得第一问,用乘法原理因子数=(a+1)*(b+1)······即得第二问。

    想到这里剩下的操作就是套+改线段树dfs序板子了(这里膜一下月老tql)

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<iostream>
      5 #include<vector>
      6 #include<queue>
      7 #include<cmath>
      8 #include<set>
      9 #define lid id<<1
     10 #define rid id<<1|1
     11 #define INF 0x3f3f3f3f
     12 #define LL long long
     13 #define debug(x) cout << "[" << x << "]" << endl
     14 using namespace std;
     15 const int maxn = 1e5+5;
     16 int b[]={2,3,5,7,11,13};
     17 int d[maxn][6]={0};
     18 void cal(int x, int *d)
     19 {
     20     for(int i = 0;i < 6 ;i++){
     21         while(x%b[i]==0)x/=b[i],d[i]++;
     22     }
     23 }
     24 const int mx = 1e5+10;
     25 const int mod = 1e9+7;
     26 int L[mx], R[mx], p[mx];
     27 struct tree{
     28     int l, r;
     29     int p[6]; //2,3,5,7,11,13
     30     int lazy[6];
     31 }tree[mx<<2];
     32 vector<int> G[mx];
     33 int cnt;
     34 LL Ans[6] = {0};
     35 
     36 LL qpow(LL x, LL n){ //x^n
     37     LL res = 1;
     38     while (n > 0){
     39         if (n & 1) res = res*x%mod;
     40         x = x*x % mod;
     41         n >>= 1;
     42     }
     43     return res;
     44 }
     45 
     46 void push_up(int id){
     47     for (int i = 0; i < 6; i++)
     48         tree[id].p[i] = tree[lid].p[i]+tree[rid].p[i];
     49 }
     50 
     51 void build(int l, int r, int id){
     52     tree[id].l = l;
     53     tree[id].r = r;
     54     for (int i = 0; i < 6; i++) tree[id].p[i] = 0;
     55     if (l == r) return;
     56     int mid = (l+r) >> 1;
     57     build(l, mid, lid);
     58     build(mid+1, r, rid);
     59 }
     60 
     61 void dfs(int u){
     62     L[u] = ++cnt;
     63     int len = G[u].size();
     64     for (int i = 0; i < len; i++){
     65         int v = G[u][i];
     66         dfs(v);
     67     }
     68     R[u] = cnt;
     69 }
     70 
     71 void upd(int c, int id, int *x){
     72     if (tree[id].l == c && tree[id].r == c){
     73         for (int i = 0; i < 6; i++)
     74             tree[id].p[i] += x[i];
     75         return;
     76     }
     77     int mid = (tree[id].l + tree[id].r)>>1;
     78     if (c <= mid) upd(c, lid, x);
     79     else upd(c, rid, x);
     80     push_up(id);
     81 }
     82 
     83 void query(int l, int r, int id){
     84     if (tree[id].l == l && tree[id].r == r){
     85         for (int i = 0; i < 6; i++)
     86             Ans[i] += tree[id].p[i];
     87         return;
     88     }
     89     int mid = (tree[id].l + tree[id].r)>>1;
     90     if (r <= mid) query(l, r, lid);
     91     else if (mid < l) query(l, r, rid);
     92     else {
     93         query(l, mid, lid);
     94         query(mid+1, r, rid);
     95     }
     96 }
     97 
     98 int main(){
     99     int n, u, v, a, q;
    100     cnt = 0;
    101     scanf("%d", &n);
    102     for (int i = 1; i < n; i++){
    103         scanf("%d%d", &u, &v);
    104         G[u].push_back(v);
    105         p[v] = u;
    106     }
    107     for (int i = 0; i < n; i++){
    108         if (!p[i]) {
    109             dfs(i);
    110             break;
    111         }
    112     }
    113     build(1, n, 1);
    114     for (int i = 0; i < n; i++){
    115         scanf("%d", &a);
    116         cal(a,d[i]);
    117         upd(L[i], 1, d[i]);
    118     }
    119     scanf("%d", &q);
    120     while (q--){
    121         char s[10];
    122         int d2[6] = {0};
    123         scanf("%s%d", s, &a);
    124         if (s[0] =='R'){
    125             memset(Ans, 0, sizeof Ans);
    126             query(L[a], R[a], 1);
    127             LL ans = 1;
    128             LL num = 1;
    129             for (int i = 0; i < 6; i++){
    130                 num = (num*qpow(b[i], Ans[i]))%mod;
    131                 ans = ans*(Ans[i]+1)%mod;
    132             }
    133             printf("%lld %lld
    ", num, ans);
    134         }
    135         else {
    136             int c;
    137             scanf("%d", &c);
    138             cal(c, d2);
    139             upd(L[a], 1, d2);
    140         }
    141     }
    142     return 0;
    143 }
    View Code
     
  • 相关阅读:
    创龙DSP6748的DAC例程研究
    LARK BOARD开发板试用第一篇-上电测试学习
    itop-4412开发板使用第一篇-信号量的学习使用
    《王阳明》读书笔记
    【原创】大叔问题定位分享(5)Kafka客户端报错SocketException: Too many open files 打开的文件过多
    【原创】大叔问题定位分享(4)Kafka集群broker节点从zookeeper上消失
    【原创】大叔问题定位分享(3)Kafka集群broker进程逐个报错退出
    【原创】大数据基础之Kafka(1)简介、安装及使用
    【原创】大叔问题定位分享(2)spark任务一定几率报错java.lang.NoSuchFieldError: HIVE_MOVE_FILES_THREAD_COUNT
    【原创】大数据基础之Quartz(1)简介、源代码解析
  • 原文地址:https://www.cnblogs.com/llllrj/p/9502071.html
Copyright © 2011-2022 走看看