题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5634
--------------------------------------------------------------------------------------------
官方题解上给的是用平衡树写 不过用类似的思路 也是可以用线段树去写的
操作$2$区间赋为相同值可以直接按照常规的线段树的题目去写
操作$1$是只减不增的 而且最多$log$次会减少到$1$
所以大量使用$1$操作会出现许多连续的$1$
当访问到区间都是一个值显然可以直接返回结果
而在这之前我们变可以把区间不为相同值的进行暴力取$phi$
尽管操作$2$会使区间值增加 但如果把连续的相同值算作$1$个区间的话
操作$2$每次最多只会增加$1$个区间 所以均摊下来并不会使操作$1$的复杂度增加
最终复杂度也是$O((n + m)logn)$的
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 const int N = 1e7, L = 7e5, T = 3e5 + 10; 7 bool used[N + 10]; 8 int phi[N + 10], p[L]; 9 int a[T], flag[T << 2]; 10 long long sum[T << 2]; 11 int len, t, n, m; 12 void getprime() 13 { 14 phi[1] = 1; 15 for(int i = 2; i <= N; ++i) 16 { 17 if(! used[i]) 18 { 19 p[++len] = i; 20 phi[i] = i - 1; 21 } 22 for(int j = 1; j <= len && i * p[j] <= N; ++j) 23 { 24 used[i * p[j]] = 1; 25 if(i % p[j] == 0) 26 { 27 phi[i * p[j]] = phi[i] * p[j]; 28 break; 29 } 30 else 31 phi[i * p[j]] = phi[i] * (p[j] - 1); 32 } 33 } 34 } 35 void build(int x, int L, int R) 36 { 37 if(L == R) 38 { 39 sum[x] = flag[x] = a[L]; 40 return; 41 } 42 int mid = (L + R) >> 1; 43 build(x << 1, L, mid); 44 build(x << 1 | 1, mid + 1, R); 45 sum[x] = sum[x << 1] + sum[x << 1 | 1]; 46 flag[x] = (flag[x << 1] == flag[x << 1 | 1] ? flag[x << 1] : 0); 47 } 48 void update2(int x, int L, int R, int tl, int tr, int y) 49 { 50 if(L <= tl && tr <= R) 51 { 52 flag[x] = y; 53 sum[x] = (long long)flag[x] * (tr - tl + 1); 54 return; 55 } 56 int mid = (tl + tr) >> 1; 57 if(flag[x]) 58 { 59 update2(x << 1, tl, mid, tl, mid, flag[x]); 60 update2(x << 1 | 1, mid + 1, tr, mid + 1, tr, flag[x]); 61 } 62 if(L <= mid) 63 update2(x << 1, L, R, tl, mid, y); 64 if(mid < R) 65 update2(x << 1 | 1, L, R, mid + 1, tr, y); 66 sum[x] = sum[x << 1] + sum[x << 1 | 1]; 67 flag[x] = (flag[x << 1] == flag[x << 1 | 1] ? flag[x << 1] : 0); 68 } 69 void update1(int x, int L, int R, int tl, int tr) 70 { 71 if(flag[x] && L <= tl && tr <= R) 72 { 73 flag[x] = phi[flag[x]]; 74 sum[x] = (long long)flag[x] * (tr - tl + 1); 75 return; 76 } 77 int mid = (tl + tr) >> 1; 78 if(flag[x]) 79 { 80 update2(x << 1, tl, mid, tl, mid, flag[x]); 81 update2(x << 1 | 1, mid + 1, tr, mid + 1, tr, flag[x]); 82 } 83 if(L <= mid) 84 update1(x << 1, L, R, tl, mid); 85 if(mid < R) 86 update1(x << 1 | 1, L, R, mid + 1, tr); 87 sum[x] = sum[x << 1] + sum[x << 1 | 1]; 88 flag[x] = (flag[x << 1] == flag[x << 1 | 1] ? flag[x << 1] : 0); 89 } 90 long long query(int x, int L, int R, int tl, int tr) 91 { 92 if(L <= tl && tr <= R) 93 return sum[x]; 94 int mid = (tl + tr) >> 1; 95 if(flag[x]) 96 { 97 update2(x << 1, tl, mid, tl, mid, flag[x]); 98 update2(x << 1 | 1, mid + 1, tr, mid + 1, tr, flag[x]); 99 } 100 long long re = 0; 101 if(L <= mid) 102 re += query(x << 1, L, R, tl, mid); 103 if(mid < R) 104 re += query(x << 1 | 1, L, R, mid + 1, tr); 105 return re; 106 } 107 int main() 108 { 109 getprime(); 110 scanf("%d", &t); 111 while(t--) 112 { 113 scanf("%d%d", &n, &m); 114 for(int i = 1; i <= n; ++i) 115 scanf("%d", &a[i]); 116 build(1, 1, n); 117 int op, x, y, z; 118 while(m--) 119 { 120 scanf("%d%d%d", &op, &x, &y); 121 if(op == 1) 122 update1(1, x, y, 1, n); 123 else if(op == 2) 124 { 125 scanf("%d", &z); 126 update2(1, x, y, 1, n, z); 127 } 128 else 129 printf("%lld\n", query(1, x, y, 1, n)); 130 } 131 } 132 return 0; 133 }
原文:http://www.cnblogs.com/sagitta/p/5204066.html