HDU 5634 Rikka with Phi

题目链接: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
", query(1, x, y, 1, n));
130         }
131     }
132     return 0;
133 }
原文地址:https://www.cnblogs.com/sagitta/p/5204066.html