Description

有一个长为 \(n\) 的序列,保证序列元素不超过 \(10^6\) 且其质因数集是前60个质数集合的子集。初始时全部都是 \(3\),有 \(m\) 次操作,要么要求支持单点修改,要么要求查询区间 \([l,~r]\) 的区间积 \(x\) 的欧拉函数值 \(\phi(x)\) 对一个质数取模的结果。

Limitation

\(1 \leq n,~m \leq 10^5\)

Solution

考虑一个公式

\[\phi(x) = \prod_{i = 1}^{60} p_i^{c_i - 1} \times (p_i - 1)
\]

证明上,考虑 \(\phi(p) = p - 1\),其中 \(p\) 是一个质数,那么对于 \(p^k\),由于它有且仅有 \(p\) 一个因数,于是 \(p^k\) 共有 \(\frac{p^k}{p} = p^{k - 1}\) 个因数,于是 \(\phi(p^k)~=~p^k - p^{k - 1}~=~p^{k-1} \times (p - 1)\)

由于欧拉函数是积性的,将每个质因子的欧拉函数乘起来即可得到上式。

于是考虑用线段树维护区间积,再状压维护区间每个质因数的出现情况,对于出现的质因数 \(p\),查询时直接将区间积乘上 \(p^{-1} \times (p - 1)\) 即可。

Code

#include <cstdio>
#include <algorithm> const int maxn = 100005;
const int MOD = 19961993; int n = 100000, q;
const int prm[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281};
const int inv[] = {9980997, 6653998, 11977196, 8555140, 5444180, 1535538, 10568114, 14708837, 3471651, 11701858, 17386252, 1618540, 16066970, 2321162, 18263100, 16948862, 12518538, 15380552, 10725847, 1686929, 13399146, 17182475, 12025297, 15924736, 13582387, 395287, 6395590, 15857658, 16299242, 6359573, 3300802, 18742940, 6702567, 10914471, 16210746, 11765678, 5340151, 18247466, 7769638, 8077107, 11932588, 6506948, 1985748, 6619521, 5877135, 4413707, 9744480, 10115270, 14597757, 16475182, 18334191, 5011379, 18885205, 7555336, 621385, 11309266, 12170137, 12006660, 18304499, 11153142}; struct Tree {
int l, r;
ll v, oc;
Tree *ls, *rs; Tree() : v(3), oc(2), ls(NULL), rs(NULL) {} inline void pushup() {
this->v = this->ls->v * this->rs->v % MOD;
this->oc = this->ls->oc | this->rs->oc;
} inline bool inrange(const int l, const int r) { return (this->l >= l) && (this->r <= r); }
inline bool outofrange(const int l, const int r) { return (this->l > r) || (this->r < l); }
};
Tree *rot; void build(Tree *const u, const int l, const int r);
void update(Tree *const u, const int p, const int v);
std::pair<ll, ll> query(Tree *const u, const int l, const int r); int main() {
freopen("1.in", "r", stdin);
qr(q);
build(rot = new Tree, 1, n);
int a, b, c;
while (q--) {
a = b = c = 0; qr(a); qr(b); qr(c);
if (a == 0) {
auto _ret = query(rot, b, c);
for (int i = 0; i < 60; ++i) if (_ret.second & (1ll << i)) {
_ret.first = _ret.first * inv[i] % MOD * (prm[i] - 1) % MOD;
}
qw(_ret.first, '\n', true);
} else {
update(rot, b, c);
}
}
return 0;
} void build(Tree *const u, const int l, const int r) {
if ((u->l = l) == (u->r = r)) return;
int mid = (l + r) >> 1;
build(u->ls = new Tree, l, mid);
build(u->rs = new Tree, mid + 1, r);
u->pushup();
} std::pair<ll, ll> query(Tree *const u, const int l, const int r) {
if (u->inrange(l, r)) {
return std::make_pair(u->v, u->oc);
} else if (u->outofrange(l, r)) {
return std::make_pair(1ll, 0ll);
} else {
auto lr = query(u->ls, l, r), rr = query(u->rs, l, r);
return std::make_pair(lr.first * rr.first % MOD, lr.second | rr.second);
}
} void update(Tree *const u, const int p, const int v) {
if (u->outofrange(p, p)) {
return;
} else if (u->l == u->r) {
u->v = v; u->oc = 0;
for (int i = 0; i < 60; ++i) if (!(v % prm[i])) {
u->oc |= 1ll << i;
}
} else {
update(u->ls, p, v); update(u->rs, p, v);
u->pushup();
}
}

【数论&线段树】【P4140】[清华集训2015]奇数国的更多相关文章

  1. 「清华集训2015」V

    「清华集训2015」V 题目大意: 你有一个序列,你需要支持区间加一个数并对 \(0\) 取 \(\max\),区间赋值,查询单点的值以及单点历史最大值. 解题思路: 观察发现,每一种修改操作都可以用 ...

  2. 清华集训2015 V

    #164. [清华集训2015]V http://uoj.ac/problem/164 统计 描述 提交 自定义测试 Picks博士观察完金星凌日后,设计了一个复杂的电阻器.为了简化题目,题目中的常数 ...

  3. 2018.07.28 uoj#164. 【清华集训2015】V(线段树)

    传送门 线段树好题. 要求支持的操作: 1.区间变成max(xi−a,0)" role="presentation" style="position: rela ...

  4. 【uoj#164】[清华集训2015]V 线段树维护历史最值

    题目描述 给你一个长度为 $n$ 的序列,支持五种操作: $1\ l\ r\ x$ :将 $[l,r]$ 内的数加上 $x$ :$2\ l\ r\ x$ :将 $[l,r]$ 内的数减去 $x$ ,并 ...

  5. UOJ #164 [清华集训2015]V (线段树)

    题目链接 http://uoj.ac/problem/164 题解 神仙线段树题. 首先赋值操作可以等价于减掉正无穷再加上\(x\). 假设某个位置从前到后的操作序列是: \(x_1,x_2,..., ...

  6. Bzoj 3813 奇数国 题解 数论+线段树+状压

    3813: 奇数国 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 748  Solved: 425[Submit][Status][Discuss] ...

  7. 【bzoj3813】: 奇数国 数论-线段树-欧拉函数

    [bzoj3813]: 奇数国 题意:给定一个序列,每个元素可以分解为最小的60个素数的形式.(x=p1^k1*p2^k2*......p60^k60)(p1=2,p2=3,…,p60=281) 支持 ...

  8. codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)

    In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 ...

  9. Codeforces 671C. Ultimate Weirdness of an Array(数论+线段树)

    看见$a_i\leq 200000$和gcd,就大概知道是要枚举gcd也就是答案了... 因为答案是max,可以发现我们很容易算出<=i的答案,但是很难求出单个i的答案,所以我们可以运用差分的思 ...

随机推荐

  1. centos7上配置mysql8的双主互写

    注意:1.主库1:10.1.131.75,主库2:10.1.131.762.server-id必须是纯数字,并且主从两个server-id在局域网内要唯一. [主节点1]vi /etc/my.cnf[ ...

  2. centos上安装grafana

    wget https://dl.grafana.com/oss/release/grafana-6.2.5-1.x86_64.rpm yum localinstall grafana-6.2.5-1. ...

  3. go-gin-api 规划目录和参数验证(二)

    概述 首先同步下项目概况: 上篇文章分享了,使用 go modules 初始化项目,这篇文章咱们分享: 规划目录结构 模型绑定和验证 自定义验证器 制定 API 返回结构 废话不多说,咱们开始吧. 规 ...

  4. Java8 LocalDateTime和Date相互转换

    很想要用Java的时间api,但有时候还是需要转换为Date. 二者的相互转换并不是一步到位那么简单,所以,还是需要记录一下转换的api Date to LocalDateTime Date toda ...

  5. 数据库IN查询参数化改造的方法

    // 批量查询的 2019-05-14 if (!string.IsNullOrWhiteSpace(Request["userCodes"])) { string userCod ...

  6. Asp.NetCoreWebApi入门 - 从零开始新建api项目

    开发环境 打开VS,建立项目 项目结构 修改 StartUp 类代码 ConfigureServices方法 Configure方法 为开发环境和生产环境配置不同的 Startup 新建一个Contr ...

  7. 使用xdebug对php做性能分析调优

    作为PHP程序员我们或多或少都了解或使用过xdebug.此文章记录安装和配置xdebug,以及如何使用它来分析php程序. 我的机器环境: mac, php 安装 xdebug 推荐使用 pecl 安 ...

  8. element admin中使用nprogress实现页面加载进度条

    主要是知道是nprogress这个组件实现的就可以了,组件的使用方法可参考:https://blog.csdn.net/ltr15036900300/article/details/47321217 ...

  9. FPM Search里给查询条件加OVS搜索帮助

    FPM里的OVS用法基本和WDA一致. 1,将OVS类添加到SEARCH.(可以单独写个类,因为这里为了方便,就和SEARCH放一起了) IF_FPM_GUIBB_OVS~HANDLE_PHASE_0 ...

  10. Centos7 安装配置 Rabbitmq Cluster

    Rabbitmq介绍 RabbitMQ是由 LShift 提供的一个 Advanced Message Queuing Protocol (AMQP) 的开源实现,由以高性能.健壮以及可伸缩性出名的 ...