HDU--5152(线段树,指数降幂公式)

2015-06-20 16:10:35

传送门

题意:给出 n个 数(n <= 50000),有三种操作:(1)区间求和,(2)将某个位置的数 x 变成 2^x ,(3)区间加值

总结:很久以前就想补的题目。也补了挺久的 TAT。

   比较难处理的是第二种操作。因为2^(2^x) mod P != 2^(2^x mod P) % mod P,所以不能直接暴力处理。

  考虑使用降幂公式:当 Y >= phi(P) 时,X^Y mod P = X^(Y % phi(P) + phi(P)) mod P (注意 P 为非质数,Y < phi(P) 时,公式不一定成立)

   比如:

   发现模数 2333333 求18次欧拉函数就会变成1,对1取模肯定是0。发现了这一点,那么对于(2)操作至多进行18次,可以直接暴力搞。由于

   在(2)操作之间可能会穿插着(3)操作,所以需要用向量来保存相邻(2)操作之间所加的值。类似这样:

   其余操作就是裸的线段树了。

  1 #include <cstdio>
  2 #include <ctime>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <cmath>
  6 #include <vector>
  7 #include <map>
  8 #include <set>
  9 #include <stack>
 10 #include <queue>
 11 #include <string>
 12 #include <iostream>
 13 #include <algorithm>
 14 using namespace std;
 15 
 16 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
 17 #define MP(a,b) make_pair(a,b)
 18 #define PB(a) push_back(a)
 19 
 20 typedef long long ll;
 21 typedef pair<int,int> pii;
 22 const double eps = 1e-8;
 23 const int INF = (1 << 30) - 1;
 24 const ll mod = 2333333;
 25 const int MAXN = 50010;
 26 
 27 ll Phi(ll v){
 28     ll top = (int)sqrt(1.0 * v);
 29     ll res = v;
 30     for(int i = 2; i <= top; ++i) if(v % i == 0){
 31         while(v % i == 0) v /= i;
 32         res = res / i * (i - 1);
 33     }
 34     if(v > 1) res = res / v * (v - 1);
 35     return res;
 36 }
 37 
 38 int N,M;
 39 ll A[MAXN],phi[30];
 40 vector<ll> G[MAXN];
 41 
 42 ll Q_pow(ll x,ll y,ll p){
 43     x %= p;
 44     ll res = 1;
 45     while(y){
 46         if(y & 1) res = res * x % p;
 47         x = x * x % p;
 48         y >>= 1;
 49     }
 50     return res;
 51 }
 52 
 53 struct SMT{
 54     ll tsum[MAXN << 2],add[MAXN << 2],len[MAXN << 2];
 55     inline void push_up(int p){
 56         tsum[p] = (tsum[p << 1] + tsum[p << 1|1]) % mod;
 57     }
 58     inline void push_down(int p){
 59         if(add[p]){
 60             add[p << 1] += add[p];
 61             add[p << 1|1] += add[p];
 62             tsum[p << 1] = (tsum[p << 1] + len[p << 1] * add[p] % mod) % mod;
 63             tsum[p << 1|1] = (tsum[p << 1|1] + len[p << 1|1] * add[p] % mod) % mod;
 64             add[p] = 0;
 65         }
 66     }
 67     void build(int p,int l,int r){
 68         add[p] = 0;
 69         len[p] = r - l + 1;
 70         if(l == r){
 71             tsum[p] = A[l] % mod;
 72             G[l].PB(A[l]);
 73             return;
 74         }
 75         int mid = getmid(l,r);
 76         build(p << 1,l,mid);
 77         build(p << 1|1,mid + 1,r);
 78         push_up(p);
 79     }
 80     ll Cal(int id,int p,int d){ // d: curent depth , top: limited depth
 81         if(d >= 19) return 0;
 82         if(p == 0)
 83             return G[id][p];
 84         ll X = Cal(id,p - 1,d + 1);
 85         if(X < phi[d]) return (Q_pow(2,X,phi[d - 1]) + G[id][p]) % phi[d - 1];
 86         return (Q_pow(2,X % phi[d] + phi[d],phi[d - 1]) + G[id][p]) % phi[d - 1];
 87     }
 88     void update1(int x,int p,int l,int r){
 89         if(l == r){
 90             if(add[p]){
 91                 G[l][G[l].size() - 1] += add[p];
 92                 add[p] = 0;
 93             }
 94             G[l].PB(0);
 95             tsum[p] = Cal(l,G[l].size() - 1,1);
 96             return;
 97         }
 98         push_down(p);
 99         int mid = getmid(l,r);
100         if(x <= mid) update1(x,p << 1,l,mid);
101         else update1(x,p << 1|1,mid + 1,r);
102         push_up(p);
103     }
104     void update2(int a,int b,int x,int p,int l,int r){
105         if(a <= l && r <= b){
106             add[p] += x;
107             tsum[p] = (tsum[p] + len[p] * x % mod) % mod;
108             return;
109         }
110         push_down(p);
111         int mid = getmid(l,r);
112         if(a <= mid) update2(a,b,x,p << 1,l,mid);
113         if(b > mid) update2(a,b,x,p << 1|1,mid + 1,r);
114         push_up(p);
115     }
116     ll query(int a,int b,int p,int l,int r){
117         if(a <= l && r <= b)
118             return tsum[p];
119         push_down(p);
120         int mid = getmid(l,r);
121         ll res = 0;
122         if(a <= mid) res = (res + query(a,b,p << 1,l,mid)) % mod;
123         if(b > mid) res = (res + query(a,b,p << 1|1,mid + 1,r)) % mod;
124         return res;
125     }
126 }smt;
127 
128 int main(){
129     int a,b,c,d;
130     // Pre Process phi
131     ll val = mod;
132     phi[0] = mod;
133     for(int i = 1; i <= 20; ++i){
134         val = Phi(val);
135         phi[i] = val;
136     }
137     while(scanf("%d %d",&N,&M) != EOF){
138         for(int i = 1; i <= N; ++i){
139             scanf("%d",&a);
140             A[i] = (ll)a;
141             G[i].clear();
142         }
143         smt.build(1,1,N);
144         for(int o = 1; o <= M; ++o){
145             scanf("%d",&a);
146             if(a == 1){
147                 scanf("%d%d",&b,&c);
148                 printf("%lld\n",smt.query(b,c,1,1,N));
149             }
150             else if(a == 2){
151                 scanf("%d",&c);
152                 smt.update1(c,1,1,N);
153             }
154             else{
155                 scanf("%d%d%d",&b,&c,&d);
156                 smt.update2(b,c,d,1,1,N);
157             }
158         }
159     }
160     return 0;
161 }

 

posted @ 2015-06-20 16:41  Naturain  阅读(280)  评论(0编辑  收藏  举报