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\n", query(1, x, y, 1, n));
130         }
131     }
132     return 0;
133 }
时间: 2024-10-29 19:12:11

HDU 5634 Rikka with Phi的相关文章

HDU 5634 Rikka with Phi 线段树

题意:bc round 73 div1 D 中文题面 分析:注意到10^7之内的数最多phi O(log(n))次就会变成1, 因此可以考虑把一段相同的不为1的数缩成一个点,用平衡树来维护. 每次求phi的时候就在平衡树上取出这个区间然后暴力求phi,如果一段数变成了1, 就在平衡树里面删掉它,最后统计答案的时候只要把区间中被删去的1加回答案即可, 时间复杂度O((n + m)logn) 注:平衡树,写起来麻烦(然后其实我也不会写) 但是题解当中说把一段相同的数缩成一个点,就很好 所以用线段树,

判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence

1 // 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence 2 // 题意:三种操作,1增加值,2开根,3求和 3 // 思路:这题与HDU 4027 和HDU 5634 差不多 4 // 注意开根号的话,遇到极差等于1的,开根号以后有可能还是差1.如 5 // 2 3 2 3... 6 // 8 9 8 9... 7 // 2 3 2 3... 8 // 8 9 8 9... 9 // 剩下就是遇到区间相等的话,就直接开根号不往下传 10 11 12

HDU 5831 Rikka with Parenthesis II(六花与括号II)

HDU 5831 Rikka with Parenthesis II (六花与括号II) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Description 题目描述 As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math ta

hdu 5425 Rikka with Tree II(暴力)

题目链接:hdu 5425 Rikka with Tree II 直接枚举就好了,当概率极小时贡献值可以忽略. #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <queue> #include <algorithm> using namespace std; const int maxn = 1e5 + 5; int N,

hdu 6085 Rikka with Candies(bitset)

题目链接:hdu 6085 Rikka with Candies 题意: 给你一个A序列和B序列,A和B内的每个数都不相同,现在有q个询问,问对于每个询问的k输出A[i]%B[j]==k的个数的奇偶性. 题解: 考虑两种情况: 1. 当A[i]<B[i]时,对于当前询问的k,只要A[i]中有k,那么大于A[i]的数都会有贡献. 2. 当A[i]>=B[i]时,如果A[i]%B[j]==k,那么会有(A[i]-k)%B[j]=0.此时只要B[j]是A[i]-k的因子就会有贡献. 所以我们将询问从

hdu 6092 Rikka with Subset(01背包)

题目链接:hdu 6092 Rikka with Subset 题意: 给你n和m,让你找一个字典序最小的含有n个数的A序列,使得A序列的和为m, 然后给你m+1个数,是A序列所有的集合的和的个数,然后让你找出这个A序列. 题解: 和题解一样的思想. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);++i) 4 using

hdu 5204 Rikka with sequence

题意: 众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的: 如果一个无重边无自环的无向图的每个联通块都存在一条回路经过这个联通分量所有边一次且仅一次,那么就称这个无向图是优美的.请问有n个点且边数不少于m的优美的图有多少个?(在这题中,我们认为这n个点是本质不同的) 当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗? 限制: 1 <= n <= 1e5; 1 <= L <= R <= 1e18; 1 <= w <=

hdu 5203 Rikka with wood sticks

题意: 勇太有一根长度为n的木棍,这个木棍是由n个长度为1的小木棍拼接而成,当然由于时间放置的久了,一些小木棍已经不牢固了,所以勇太想让六花把这个木棍分成正整数长度的4段,其中有3段要没有不牢固的小木棍,勇太希望这3段木棍的长度和可以最大.同时六花希望在满足勇太要求的情况下让这三根木棍能拼成一个三角形,请问萌萌哒六花有多少种可行的分割方案呢? 限制: 1 <= n <= 1e6; 1 <= m <= 1e3 思路: 实际上问题会化为: 1. 给出长度为l1,l2的木棒,把其中一根截

HDU5634 Rikka with Phi 线段树

1 // HDU5634 Rikka with Phi 线段树 2 // 思路:操作1的时候,判断一下当前区间是不是每个数都相等,在每个数相等的区间上操作.相当于lazy,不必更新到底. 3 4 5 #include <bits/stdc++.h> 6 using namespace std; 7 #define clc(a,b) memset(a,b,sizeof(a)) 8 #define inf 0x3f3f3f3f 9 #define lson l,mid,rt<<1 10