HDU 5634 Rikka with Phi

本文介绍了一种利用线段树解决特定区间操作问题的方法,包括区间赋值和区间减少操作,通过预处理和分治策略实现复杂度优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: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 }

 

转载于:https://www.cnblogs.com/sagitta/p/5204066.html

基于Spring Boot搭建的一个多功能在线学习系统的实现细节。系统分为管理员和用户两个主要模块。管理员负责视频、文件和文章资料的管理以及系统运营维护;用户则可以进行视频播放、资料下载、参与学习论坛并享受个性化学习服务。文中重点探讨了文件下载的安全性和性能优化(如使用Resource对象避免内存溢出),积分排行榜的高效实现(采用Redis Sorted Set结构),敏感词过滤机制(利用DFA算法构建内存过滤树)以及视频播放的浏览器兼容性解决方案(通过FFmpeg调整MOOV原子位置)。此外,还提到了权限管理方面自定义动态加载器的应用,提高了系统的灵活性和易用性。 适合人群:对Spring Boot有一定了解,希望深入理解其实际应用的技术人员,尤其是从事在线教育平台开发的相关从业者。 使用场景及目标:适用于需要快速搭建稳定高效的在线学习平台的企业或团队。目标在于提供一套完整的解决方案,涵盖从资源管理到用户体验优化等多个方面,帮助开发者更好地理解和掌握Spring Boot框架的实际运用技巧。 其他说明:文中不仅提供了具体的代码示例和技术思路,还分享了许多实践经验教训,对于提高项目质量有着重要的指导意义。同时强调了安全性、性能优化等方面的重要性,确保系统能够应对大规模用户的并发访问需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值