TJOI2018 数学计算
Posted youxam
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TJOI2018 数学计算相关的知识,希望对你有一定的参考价值。
题目
小豆现在有一个数 (x) ,初始值为 (1) 。 小豆有 (Q) 次操作,操作有两种类型:
-
(m): (x=x×m),输出 (xmod M) ;
-
(pos): (x=x/) 第 (pos) 次操作所乘的数(保证第 (pos) 次操作一定为类型 (1),对于每一个类型 (1) 的操作至多会被除一次),输出 (xmod M) 。
输入格式
一共有 (t) 组输入。
对于每一组输入,第一行是两个数字 (Q,M) 。
接下来 (Q) 行,每一行为操作类型 (op) ,操作编号或所乘的数字 (m) (保证所有的输入都是合法的)。
输出格式
对于每一个操作,输出一行,包含操作执行后的 (xmod M)的值
样例输入
1
10 1000000000
1 2
2 1
1 2
1 10
2 3
2 4
1 6
1 7
1 12
2 7
样例输出
2
1
2
20
10
1
6
42
504
84
数据范围
对于 (20\%) 的数据, (1≤Q≤500) ;
对于 (100\%) 的数据, (1≤Q≤10^5,t≤5,M≤10^9) 。
题解
使用线段树存储区间积, 每次除改回来一个点
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 10;
int n, p;
struct Tree {
struct Data { int L, r, mul; } data[N << 2];
void build(int v, int L, int r) {
data[v] = (Data){L, r, 1};
if (L == r) return;
int mid = L + r >> 1;
build(v << 1, L, mid), build(v << 1 | 1, mid + 1, r);
}
void update(int v, int A, int b, int k) {
if (data[v].L > b || data[v].r < A) return;
if (A <= data[v].L && data[v].r <= b)
return data[v].mul = 1ll * data[v].mul * k % p, void();
update(v << 1, A, b, k), update(v << 1 | 1, A, b, k);
}
void query(int v, int k) {
k = 1ll * k * data[v].mul % p;
if (data[v].L == data[v].r) return printf("%d
", k), void();
query(v << 1, k), query(v << 1 | 1, k);
}
} tree;
struct OP { int pos, m; } a[N];
signed main() {
int T;
scanf("%lld", &T);
while (T--) {
scanf("%lld%lld", &n, &p);
tree.build(1, 1, n);
for (int i = 1; i <= n; i++) {
int op, x;
scanf("%lld%lld", &op, &x);
if (op == 1) a[i] = (OP){i, x};
else {
tree.update(1, a[x].pos, i - 1, a[x].m);
a[x] = (OP){0, 0};
}
}
for (int i = 1; i <= n; i++)
if (a[i].pos) tree.update(1, a[i].pos, n, a[i].m);
for (int i = 1; i <= n; i++) a[i] = (OP){0, 0};
tree.query(1, 1);
}
return 0;
}
以上是关于TJOI2018 数学计算的主要内容,如果未能解决你的问题,请参考以下文章