Gym-101466K Random Numbers(线段树,数学,唯一分解定理)

给一棵树,树上每个节点有一个权值,有两个操作,RAND操作查询u的子树乘积是多少以及有多少因数,SEED操作把节点u乘上v

n,q <= 1e5。数值小于等于1e9,最大的质因数不超过13

组队训练和队友一起写的,写到头昏,代码也是合力完成的,我数学几乎为0,数学部分感谢队友@lllrj抬一手

思路:首先由于乘积的值过大,线段树不能直接维护权值,考虑到查询的是因数个数,所以线段树直接维护2,3,5,7,11,13的指数,乘一个数就是把这个数质因数分解再单点更新,查询就是区间求和,乘积用快速幂计算,至于因数的个数由唯一分解定理可知,把一个数分解质因数变成(x1^n1)*(x2^n2)*(x3^n3)......的形式,因数的个数就是(n1+1)*(n2+1)*(n3+1).....然后两个结果都要对1e9+7取模,比赛时后一个结果忘记取模浪费了快一个小时。。。

建树的话就是按dfs序建树,也是个常见套路,参见HDU-3974。需要注意按dfs序建树之后不能直接用编号的权值去建(比如a【3】不一定在线段树【3,3】这个点上),所以是先建树,输入的时候做更新

AC代码:217ms,29.4MB

  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                 //debug(Ans[i]);
131                 num = (num*qpow(b[i], Ans[i]))%mod;
132                 ans = ans*(Ans[i]+1)%mod;
133             }
134             printf("%lld %lld
", num, ans);
135         }
136         else {
137             int c;
138             scanf("%d", &c);
139             cal(c, d2);
140             upd(L[a], 1, d2);
141         }
142     }
143     return 0;
144 }
View Code

赛后微调(并没有什么改变):202ms,27MB

  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 
 16 int b[] = {2, 3, 5, 7, 11, 13};
 17 const int mx = 1e5+10;
 18 const int mod = 1e9+7;
 19 int L[mx], R[mx], p[mx];
 20 struct tree{
 21     int l, r;
 22     int p[6];
 23     int lazy[6];
 24 }tree[mx<<2];
 25 vector<int> G[mx];
 26 int cnt = 0;
 27 LL Ans[6] = {0};
 28 
 29 void cal(int x, int *d){
 30     for(int i = 0; i < 6 ; i++){
 31         while(x % b[i] == 0){
 32             x /= b[i];
 33             d[i]++;
 34         }
 35     }
 36 }
 37 
 38 LL qpow(LL x, LL n){ //x^n
 39     LL res = 1;
 40     while (n > 0){
 41         if (n & 1) res = res*x%mod;
 42         x = x*x % mod;
 43         n >>= 1;
 44     }
 45     return res;
 46 }
 47 
 48 void push_up(int id){
 49     for (int i = 0; i < 6; i++)
 50         tree[id].p[i] = tree[lid].p[i]+tree[rid].p[i];
 51 }
 52 
 53 void build(int l, int r, int id){
 54     tree[id].l = l;
 55     tree[id].r = r;
 56     for (int i = 0; i < 6; i++) tree[id].p[i] = 0;
 57     if (l == r) return;
 58     int mid = (l+r) >> 1;
 59     build(l, mid, lid);
 60     build(mid+1, r, rid);
 61 }
 62 
 63 void dfs(int u){
 64     L[u] = ++cnt;
 65     int len = G[u].size();
 66     for (int i = 0; i < len; i++){
 67         int v = G[u][i];
 68         dfs(v);
 69     }
 70     R[u] = cnt;
 71 }
 72 
 73 void upd(int c, int id, int *x){
 74     if (tree[id].l == c && tree[id].r == c){
 75         for (int i = 0; i < 6; i++)
 76             tree[id].p[i] += x[i];
 77         return;
 78     }
 79     int mid = (tree[id].l + tree[id].r)>>1;
 80     if (c <= mid) upd(c, lid, x);
 81     else upd(c, rid, x);
 82     push_up(id);
 83 }
 84 
 85 void query(int l, int r, int id){
 86     if (tree[id].l == l && tree[id].r == r){
 87         for (int i = 0; i < 6; i++)
 88             Ans[i] += tree[id].p[i];
 89         return;
 90     }
 91     int mid = (tree[id].l + tree[id].r)>>1;
 92     if (r <= mid) query(l, r, lid);
 93     else if (mid < l) query(l, r, rid);
 94     else {
 95         query(l, mid, lid);
 96         query(mid+1, r, rid);
 97     }
 98 }
 99 
100 int main(){
101     int n, u, v, a, q;
102     scanf("%d", &n);
103     for (int i = 1; i < n; i++){
104         scanf("%d%d", &u, &v);
105         G[u].push_back(v);
106         p[v] = u;
107     }
108     for (int i = 0; i < n; i++){
109         if (!p[i]) {
110             dfs(i);
111             break;
112         }
113     }
114     build(1, n, 1);
115     for (int i = 0; i < n; i++){
116         int d[6] = {0};
117         scanf("%d", &a);
118         cal(a, d);
119         upd(L[i], 1, d);
120     }
121     scanf("%d", &q);
122     while (q--){
123         char s[10];
124         scanf("%s%d", s, &a);
125         if (s[0] == 'R'){
126             memset(Ans, 0, sizeof Ans);
127             query(L[a], R[a], 1);
128             LL ans = 1, 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             int d2[6] = {0};
138             scanf("%d", &c);
139             cal(c, d2);
140             upd(L[a], 1, d2);
141         }
142     }
143     return 0;
144 }
View Code
原文地址:https://www.cnblogs.com/QAQorz/p/9501783.html