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

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

题目:

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

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

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

题意:

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

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

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

思路:

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

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

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

代码实现如下:

 #include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<int, ll> pil;;
typedef pair<int, int> pii;
typedef unsigned long long ull; #define lson i<<1
#define rson i<<1|1
#define lowbit(x) x&(-x)
#define bug printf("*********\n");
#define debug(x) cout<<"["<<x<<"]" <<endl;
#define FIN freopen("D://code//in.txt", "r", stdin);
#define IO ios::sync_with_stdio(false),cin.tie(0); const double eps = 1e-;
const int mod = 1e9 + ;
const int maxn = 1e5 + ;
const int mx = 1e4 + ;
const double pi = acos(-);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f; int n, tot, q, u, v, x, p, a, b;
char op[];
int prime[] = {, , , , , }, cnt[], ans[];
int val[maxn], head[maxn], s[maxn], t[maxn]; struct edge {
int v, next;
}ed[maxn]; struct node {
int l, r;
int num[];
}segtree[maxn<<]; void addedge(int u, int v) {
ed[tot].v = v;
ed[tot].next = head[u];
head[u] = tot++;
} void dfs(int u) {
s[u] = ++x;
for(int i = head[u]; ~i; i = ed[i].next) {
int v = ed[i].v;
dfs(v);
}
t[u] = x;
} void push_up(int i) {
for(int j = ; j < ; j++) {
segtree[i].num[j] = (segtree[lson].num[j] + segtree[rson].num[j]) % mod;
}
} void build(int i, int l, int r) {
segtree[i].l = l, segtree[i].r = r;
for(int j = ; j < ; j++) {
segtree[i].num[j] = ;
}
if(l == r) {
for(int j = ; j < ; j++) {
if(val[l] % prime[j] == ) {
while(val[l] % prime[j] == ) {
segtree[i].num[j]++;
val[l] /= prime[j];
}
}
}
return;
}
int mid = (l + r) >> ;
build(lson, l, mid);
build(rson, mid + , r);
push_up(i);
} void update(int i, int pos, int cnt[]) {
if(segtree[i].l == pos && segtree[i].r == pos) {
for(int j = ; j < ; j++) {
segtree[i].num[j] = (segtree[i].num[j] + cnt[j]) % mod;
}
return;
}
int mid = (segtree[i].l + segtree[i].r) >> ;
if(pos <= mid) update(lson, pos, cnt);
else update(rson, pos, cnt);
push_up(i);
} int Mod_Pow(int x, int n) {
int res = ;
while(n) {
if(n & ) res = (ll) res * x % mod;
x = (ll)x * x % mod;
n >>= ;
}
return res;
} void query(int i, int l, int r, int ans[]) {
if(segtree[i].l == l && segtree[i].r == r) {
for(int j = ; j < ; j++) {
ans[j] += segtree[i].num[j];
}
return;
}
int mid = (segtree[i].l + segtree[i].r) >> ;
if(r <= mid) query(lson, l, r, ans);
else if(l > mid) query(rson, l, r, ans);
else {
query(lson, l, mid, ans);
query(rson, mid + , r, ans);
}
} int main() {
//FIN;
tot = x = ;
memset(head, -, sizeof(head));
scanf("%d", &n);
for(int i = ; i < n; i++) {
scanf("%d%d", &u, &v);
u++, v++;
addedge(u, v);
}
dfs();
for(int i = ; i <= n; i++) {
scanf("%d", &p);
val[s[i]] = p;
}
build(, , n);
scanf("%d", &q);
while(q--) {
scanf("%s", op);
if(op[] == 'R') {
scanf("%d", &a);
a++;
for(int i = ; i < ; i++) ans[i] = ;
query(, s[a], t[a], ans);
ll cnt1 = , cnt2 = ;
for(int i = ; i < ; i++) {
cnt2 = (cnt2 * (( + ans[i]) % mod)) % mod;
cnt1 = (cnt1 * Mod_Pow(prime[i], ans[i])) % mod;
}
printf("%lld %lld\n", cnt1, cnt2);
} else {
scanf("%d%d", &a, &b);
a++;
for(int j = ; j < ; j++) {
cnt[j] = ;
if(b % prime[j] == ) {
while(b % prime[j] == ) {
cnt[j]++;
b /= prime[j];
}
}
}
update(, s[a], cnt);
}
}
return ;
}
上一篇:nginx grpc 试用


下一篇:GridView控件RowDataBound事件中获取列字段值的几种途径