题目链接: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)$的

 #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 1e7, L = 7e5, T = 3e5 + ;
bool used[N + ];
int phi[N + ], p[L];
int a[T], flag[T << ];
long long sum[T << ];
int len, t, n, m;
void getprime()
{
phi[] = ;
for(int i = ; i <= N; ++i)
{
if(! used[i])
{
p[++len] = i;
phi[i] = i - ;
}
for(int j = ; j <= len && i * p[j] <= N; ++j)
{
used[i * p[j]] = ;
if(i % p[j] == )
{
phi[i * p[j]] = phi[i] * p[j];
break;
}
else
phi[i * p[j]] = phi[i] * (p[j] - );
}
}
}
void build(int x, int L, int R)
{
if(L == R)
{
sum[x] = flag[x] = a[L];
return;
}
int mid = (L + R) >> ;
build(x << , L, mid);
build(x << | , mid + , R);
sum[x] = sum[x << ] + sum[x << | ];
flag[x] = (flag[x << ] == flag[x << | ] ? flag[x << ] : );
}
void update2(int x, int L, int R, int tl, int tr, int y)
{
if(L <= tl && tr <= R)
{
flag[x] = y;
sum[x] = (long long)flag[x] * (tr - tl + );
return;
}
int mid = (tl + tr) >> ;
if(flag[x])
{
update2(x << , tl, mid, tl, mid, flag[x]);
update2(x << | , mid + , tr, mid + , tr, flag[x]);
}
if(L <= mid)
update2(x << , L, R, tl, mid, y);
if(mid < R)
update2(x << | , L, R, mid + , tr, y);
sum[x] = sum[x << ] + sum[x << | ];
flag[x] = (flag[x << ] == flag[x << | ] ? flag[x << ] : );
}
void update1(int x, int L, int R, int tl, int tr)
{
if(flag[x] && L <= tl && tr <= R)
{
flag[x] = phi[flag[x]];
sum[x] = (long long)flag[x] * (tr - tl + );
return;
}
int mid = (tl + tr) >> ;
if(flag[x])
{
update2(x << , tl, mid, tl, mid, flag[x]);
update2(x << | , mid + , tr, mid + , tr, flag[x]);
}
if(L <= mid)
update1(x << , L, R, tl, mid);
if(mid < R)
update1(x << | , L, R, mid + , tr);
sum[x] = sum[x << ] + sum[x << | ];
flag[x] = (flag[x << ] == flag[x << | ] ? flag[x << ] : );
}
long long query(int x, int L, int R, int tl, int tr)
{
if(L <= tl && tr <= R)
return sum[x];
int mid = (tl + tr) >> ;
if(flag[x])
{
update2(x << , tl, mid, tl, mid, flag[x]);
update2(x << | , mid + , tr, mid + , tr, flag[x]);
}
long long re = ;
if(L <= mid)
re += query(x << , L, R, tl, mid);
if(mid < R)
re += query(x << | , L, R, mid + , tr);
return re;
}
int main()
{
getprime();
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++i)
scanf("%d", &a[i]);
build(, , n);
int op, x, y, z;
while(m--)
{
scanf("%d%d%d", &op, &x, &y);
if(op == )
update1(, x, y, , n);
else if(op == )
{
scanf("%d", &z);
update2(, x, y, , n, z);
}
else
printf("%lld\n", query(, x, y, , n));
}
}
return ;
}

HDU 5634 Rikka with Phi的更多相关文章

  1. HDU 5634 Rikka with Phi 线段树

    题意:bc round 73 div1 D 中文题面 分析:注意到10^7之内的数最多phi O(log(n))次就会变成1, 因此可以考虑把一段相同的不为1的数缩成一个点,用平衡树来维护. 每次求p ...

  2. 2018.07.03 HDU Rikka with Phi(线段树)

    Rikka with Phi Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) P ...

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

    // 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence // 题意:三种操作,1增加值,2开根,3求和 // 思路:这题与HDU 4027 和HDU 5634 ...

  4. HDU 6088 - Rikka with Rock-paper-scissors | 2017 Multi-University Training Contest 5

    思路和任意模数FFT模板都来自 这里 看了一晚上那篇<再探快速傅里叶变换>还是懵得不行,可能水平还没到- - 只能先存个模板了,这题单模数NTT跑了5.9s,没敢写三模数NTT,可能姿势太 ...

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

    31 Rikka with Parenthesis II (六花与括号II) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536 ...

  6. HDU5634 Rikka with Phi 线段树

    // HDU5634 Rikka with Phi 线段树 // 思路:操作1的时候,判断一下当前区间是不是每个数都相等,在每个数相等的区间上操作.相当于lazy,不必更新到底. #include & ...

  7. Rikka with Phi 线段树

    Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds ...

  8. HDU 6091 - Rikka with Match | 2017 Multi-University Training Contest 5

    思路来自 某FXXL 不过复杂度咋算的.. /* HDU 6091 - Rikka with Match [ 树形DP ] | 2017 Multi-University Training Conte ...

  9. HDU 6093 - Rikka with Number | 2017 Multi-University Training Contest 5

    JAVA+大数搞了一遍- - 不是很麻烦- - /* HDU 6093 - Rikka with Number [ 进制转换,康托展开,大数 ] | 2017 Multi-University Tra ...

随机推荐

  1. java jdk12,安装路径没有jre文件夹

    (平台备注:win10系统,自测) 1.造成原因:JDK11之后没有直接的jre,要用户选择jre模块 2.如果需要,执行以下步骤可生成: 2.1 进入jdk安装目录下, 2.2 点击shift+右键 ...

  2. El 表达式和 Jstl 标签库

    El 表达式学习 1. 什么是 EL 表达式 全称:Expression Language,一种写法非常简介的表达式.语法简单易懂,便于使用.表达式语言的灵感来自于 ECMAScript 和XPath ...

  3. 【题解】1-2-K Game

    题目大意   现有\(n\)个东西,每次可以取\(1\)个,\(2\)个或\(k\)个.Alice和Bob轮流取,且Alice先取.问谁是最后一个取的.(\(0 \leq n \leq 10^9\), ...

  4. HTML+CSS ,原型

    此图是别人所作

  5. (二:NIO系列) Java NIO Buffer

    出处:Java NIO Buffer Buffer是一个抽象类,位于java.nio包中,主要用作缓冲区.Buffer缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包装成NIO ...

  6. 「Vue.js」Vue-Router + Webpack 路由懒加载实现

    一.前言 当打包构建应用时,Javascript 包会变得非常大,影响页面加载.如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了.结合 Vue ...

  7. 把java(springboot)程序打包docker镜像

    前言:要在docker运行java(jar包)程序,就要把程序打包成docker镜像(以下简称镜像),可以先理解为镜像就是jar包 打包需要程序代码,java本身的打包环境(包括jdk和maven), ...

  8. Kali系统 metasploit 使用教程

    基础配置 由于kali 2.0 已经没有metasploit 这个服务了,所以service metasploit start 的方式不起作用. 在kali 2.0中启动带数据库支持的MSF方式如下: ...

  9. CSS3进度条动画

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  10. 【汇总目录】eShopOnContainers

    随笔分类 - eShopOnContainers eShopOnContainers 知多少[10]:部署到 K8S | AKS 摘要:1. 引言 断断续续,感觉这个系列又要半途而废了.趁着假期,赶紧 ...