题目大意
题目大意是这样对于一个数字x,有若干种操作:
- 操作1是对x乘上一个数字m
- 操作2是让x第pos次的操作失效
每次操作后输出当前x对一个数字取模的值。这个问题乍一看挺简单,但是由于取模的数字不一定是质数,所以逆元也不能用了,暴力做法不行我们就思考一些巧妙的方法。通过时间当作下标来把这些m组织起来,再用线段树维护所有段的乘积,操作1就是把当前时间对应的值置为m,操作2就是把当前时间对应的值置为1。
由于每次都需要精确递归到长度为1的段,所以标记也不需要打,直接开干。
代码
#include <cstdio>
#include <algorithm>
using namespace std;
#define lc k<<1
#define rc k<<1|1
typedef long long ll;
const int maxn = 1e5+5;
ll a[maxn], f[maxn*4];
int q, M;
void build(int k, int l, int r) {
f[k] = 1;
if(l == r) return;
int m = (l+r) >> 1;
build(lc, l, m);
build(rc, m+1, r);
}
inline void mul(int k, int l, int r, int t, int p) {
if(l == r) { f[k] = p; return; }
int m = (l+r) >> 1;
if(t <= m) {
mul(lc, l, m, t, p);
} else
mul(rc, m+1, r, t, p);
f[k] = (f[lc]*f[rc])%M;
}
inline void div(int k, int l, int r, int t) {
if(l == r) { f[k] = 1; return; }
int m = (l+r) >> 1;
if(t <= m) {
div(lc, l, m, t);
} else
div(rc, m+1, r, t);
f[k] = (f[lc]*f[rc])%M;
}
int main(void)
{
freopen("in.txt", "r", stdin);
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &q, &M);
build(1, 1, q);
int op, p;
for(int i = 1; i <= q; ++i) {
scanf("%d%d", &op, &p);
if(op == 1) {
mul(1, 1, q, i, p);
} else {
div(1, 1, q, p);
}
printf("%lld\n", f[1]%M);
}
}
return 0;
}