K. Random Numbers(Gym 101466K + 线段树 + dfs序 + 快速幂 + 唯一分解)

题目链接:http://codeforces.com/gym/101466/problem/K

题目:

题意:

  给你一棵有n个节点的树,根节点始终为0,有两种操作:

    1.RAND:查询以u为根节点的子树上的所有节点的权值的乘积x,及x的因数个数。

    2.SEED:将节点u的权值乘以x。

思路:

  比赛时少看了因数不大于13这句话,然后本题难度增加数倍,肝了两个小时都没肝出来,对不起队友啊,今天的组队训练赛实力背锅……

  这题一眼线段树,由于是对一棵子树进行处理,因此我们采用常规套路,借助dfs序将子树变成区间。不过因为权值的乘积太大,还要取模,一个数取模后因数个数也会发生变化,所以我们肯定不能用它的权值来进行建树,因而我们可以将思路进行转化,先将它的每个节点的权值进行唯一分解,对指数进行建树。

  对于最后的答案,第一个乘积x很容易求,用快速幂对2,3,5,7,11,13这六个素数进行处理即可。而第二个答案,我们根据数论知识知道它的结果是∏(1+ci),其中ci为某个因数pi的指数。

代码实现如下:

  1 #include <set>
  2 #include <map>
  3 #include <queue>
  4 #include <stack>
  5 #include <cmath>
  6 #include <bitset>
  7 #include <cstdio>
  8 #include <string>
  9 #include <vector>
 10 #include <cstdlib>
 11 #include <cstring>
 12 #include <iostream>
 13 #include <algorithm>
 14 using namespace std;
 15
 16 typedef long long ll;
 17 typedef pair<ll, ll> pll;
 18 typedef pair<ll, int> pli;
 19 typedef pair<int, ll> pil;;
 20 typedef pair<int, int> pii;
 21 typedef unsigned long long ull;
 22
 23 #define lson i<<1
 24 #define rson i<<1|1
 25 #define lowbit(x) x&(-x)
 26 #define bug printf("*********\n");
 27 #define debug(x) cout<<"["<<x<<"]" <<endl;
 28 #define FIN freopen("D://code//in.txt", "r", stdin);
 29 #define IO ios::sync_with_stdio(false),cin.tie(0);
 30
 31 const double eps = 1e-8;
 32 const int mod = 1e9 + 7;
 33 const int maxn = 1e5 + 7;
 34 const int mx = 1e4 + 7;
 35 const double pi = acos(-1);
 36 const int inf = 0x3f3f3f3f;
 37 const ll INF = 0x3f3f3f3f3f3f3f3f;
 38
 39 int n, tot, q, u, v, x, p, a, b;
 40 char op[10];
 41 int prime[6] = {2, 3, 5, 7, 11, 13}, cnt[6], ans[6];
 42 int val[maxn], head[maxn], s[maxn], t[maxn];
 43
 44 struct edge {
 45     int v, next;
 46 }ed[maxn];
 47
 48 struct node {
 49     int l, r;
 50     int num[6];
 51 }segtree[maxn<<2];
 52
 53 void addedge(int u, int v) {
 54     ed[tot].v = v;
 55     ed[tot].next = head[u];
 56     head[u] = tot++;
 57 }
 58
 59 void dfs(int u) {
 60     s[u] = ++x;
 61     for(int i = head[u]; ~i; i = ed[i].next) {
 62         int v = ed[i].v;
 63         dfs(v);
 64     }
 65     t[u] = x;
 66 }
 67
 68 void push_up(int i) {
 69     for(int j = 0; j < 6; j++) {
 70         segtree[i].num[j] = (segtree[lson].num[j] + segtree[rson].num[j]) % mod;
 71     }
 72 }
 73
 74 void build(int i, int l, int r) {
 75     segtree[i].l = l, segtree[i].r = r;
 76     for(int j = 0; j < 6; j++) {
 77         segtree[i].num[j] = 0;
 78     }
 79     if(l == r) {
 80         for(int j = 0; j < 6; j++) {
 81             if(val[l] % prime[j] == 0) {
 82                 while(val[l] % prime[j] == 0) {
 83                     segtree[i].num[j]++;
 84                     val[l] /= prime[j];
 85                 }
 86             }
 87         }
 88         return;
 89     }
 90     int mid = (l + r) >> 1;
 91     build(lson, l, mid);
 92     build(rson, mid + 1, r);
 93     push_up(i);
 94 }
 95
 96 void update(int i, int pos, int cnt[]) {
 97     if(segtree[i].l == pos && segtree[i].r == pos) {
 98         for(int j = 0; j < 6; j++) {
 99             segtree[i].num[j] = (segtree[i].num[j] + cnt[j]) % mod;
100         }
101         return;
102     }
103     int mid = (segtree[i].l + segtree[i].r) >> 1;
104     if(pos <= mid) update(lson, pos, cnt);
105     else update(rson, pos, cnt);
106     push_up(i);
107 }
108
109 int Mod_Pow(int x, int n) {
110     int res = 1;
111     while(n) {
112         if(n & 1) res = (ll) res * x % mod;
113         x = (ll)x * x % mod;
114         n >>= 1;
115     }
116     return res;
117 }
118
119 void query(int i, int l, int r, int ans[]) {
120     if(segtree[i].l == l && segtree[i].r == r) {
121         for(int j = 0; j < 6; j++) {
122             ans[j] += segtree[i].num[j];
123         }
124         return;
125     }
126     int mid = (segtree[i].l + segtree[i].r) >> 1;
127     if(r <= mid) query(lson, l, r, ans);
128     else if(l > mid) query(rson, l, r, ans);
129     else {
130         query(lson, l, mid, ans);
131         query(rson, mid + 1, r, ans);
132     }
133 }
134
135 int main() {
136     //FIN;
137     tot = x = 0;
138     memset(head, -1, sizeof(head));
139     scanf("%d", &n);
140     for(int i = 1; i < n; i++) {
141         scanf("%d%d", &u, &v);
142         u++, v++;
143         addedge(u, v);
144     }
145     dfs(1);
146     for(int i = 1; i <= n; i++) {
147         scanf("%d", &p);
148         val[s[i]] = p;
149     }
150     build(1, 1, n);
151     scanf("%d", &q);
152     while(q--) {
153         scanf("%s", op);
154         if(op[0] == ‘R‘) {
155             scanf("%d", &a);
156             a++;
157             for(int i = 0; i < 6; i++) ans[i] = 0;
158             query(1, s[a], t[a], ans);
159             ll cnt1 = 1, cnt2 = 1;
160             for(int i = 0; i < 6; i++) {
161                 cnt2 = (cnt2 * ((1 + ans[i]) % mod)) % mod;
162                 cnt1 = (cnt1 * Mod_Pow(prime[i], ans[i])) % mod;
163             }
164             printf("%lld %lld\n", cnt1, cnt2);
165         } else {
166             scanf("%d%d", &a, &b);
167             a++;
168             for(int j = 0; j < 6; j++) {
169                 cnt[j] = 0;
170                 if(b % prime[j] == 0) {
171                     while(b % prime[j] == 0) {
172                         cnt[j]++;
173                         b /= prime[j];
174                     }
175                 }
176             }
177             update(1, s[a], cnt);
178         }
179     }
180     return 0;
181 }

原文地址:https://www.cnblogs.com/Dillonh/p/9502421.html

时间: 2024-08-24 00:08:30

K. Random Numbers(Gym 101466K + 线段树 + dfs序 + 快速幂 + 唯一分解)的相关文章

Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB 总提交次数:196   AC次数:65   平均分:58.62 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 2013中国国家集训队第二次作业 问题描述 给定一棵N个节点的树,每个点有一个权值,有M个询问(a,b,c)若a 为1,回答b到c路径上的最小权值,若a为2,回答b到c路径上的最大权值,若a为3,回答b到c路径上的所有权值的

线段树+dfs序(Apple Tree )(Assign the task )

线段树+dfs序 给定一棵n个节点的树,m次查询,每次查询需要求出某个节点深度为h的所有子节点. 作为预处理,首先将树的所有节点按深度保存起来,每个深度的所有节点用一个线性结构保存,每个深度的节点相对顺序要和前序遍历一致. 然后从树的根节点进行dfs,对于每个节点记录两个信息,一个是dfs进入该节点的时间戳in[id],另一个是dfs离开该节点的时间戳out[id]. 最后对于每次查询,求节点v在深度h的所有子节点,只需将深度为h并且dfs进入时间戳在in[v]和out[v]之间的所有节点都求出

Codeforces 384E 线段树+dfs序

题目链接:点击打开链接 题意: 给定n个点,m个询问的无向树(1为根) 下面n个数表示每个点的权值 下面n-1行给出树 操作1:x点权值+v, x的第 i & 1 的儿子-v, 第 !(i&1) 的儿子+v 操作2:询问x点权值 dfs把树转成序列 根据深度把点分成2组 分别用线段树维护.. 然后Y一下 #include<stdio.h> #include<string.h> #include<iostream> #include<algorith

HDU 5692 线段树+dfs序

Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1779    Accepted Submission(s): 427 Problem Description 百度科技园内有n 个零食机,零食机之间通过n−1 条路相互连通.每个零食机都有一个值v ,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充,零食机的价值v

苹果树(线段树+Dfs序)

1228 苹果树 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结出很多的苹果.卡卡非常喜欢吃苹果,所以他一直都精心的呵护这棵苹果树.我们知道树是有很多分叉点的,苹果会长在枝条的分叉点上面,且不会有两个苹果结在一起.卡卡很想知道一个分叉点所代表的子树上所结的苹果的数目,以便研究苹果树哪些枝条的结果能力比较强. 卡卡所知道的是,每隔一些时间,某些分叉点上会结出一些苹果,但

【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形

【codevs1228】苹果树【线段树+dfs序】

题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结出很多的苹果.卡卡非常喜欢吃苹果,所以他一直都精心的呵护这棵苹果树.我们知道树是有很多分叉点的,苹果会长在枝条的分叉点上面,且不会有两个苹果结在一起.卡卡很想知道一个分叉点所代表的子树上所结的苹果的数目,以便研究苹果树哪些枝条的结果能力比较强. 卡卡所知道的是,每隔一些时间,某些分叉点上会结出一些苹果,但是卡卡所不知道的是,总会有一些调皮的小孩来树上摘走一些苹果. 于是我们定义两种操作: C x 表示编号为x

BZOJ_3252_攻略_线段树+dfs序

Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏<XX 半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状 结构:开始游戏时在根节点(共通线),叶子节点为结局.每个场景有一个价值,现在桂马开启攻略之神模式,同 时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的) “为什么你还没玩就知道每个场景的价

HDU5692(线段树+dfs序)

Snacks Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Description 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通.每个零食机都有一个值v,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化.小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次.另外,小度熊会对某个零食机的零食有所偏爱,要求