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 }