【Luogu P4588】 [TJOI2018]数学计算
题目链接:
正文:
如果模数是质数的话就可以直接用逆元,可惜它不是。
那我们先考虑朴素算法,设 \(a_i\) 表示为第 \(i\) 次所乘的数,如果第 \(i\) 次类型是 2,那么 \(a_i\) 就为 \(1\)。
这样下来,每次读入后用 \(O(n)\) 的时间把 \(a\) 全部乘起来就能得到答案了。
考虑优化它,这个朴素看上去只有区间积,那么我们可以用线段树来优化它,单点修改、区间查询。接着就是线段树的板子了。
代码:
struct Segment
{
struct Seg
{
ll val, l, r;
}t[N * 4];
void build(int p, int l, int r)
{
t[p].l = l, t[p].r = r;
if(l == r) {t[p].val = 1; return ;}
int mid = l + r >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
t[p].val = t[p << 1].val * t[p << 1 | 1].val % mod;
}
void change(int p, int x, ll val)
{
if(t[p].l == t[p].r) {t[p].val = val; return;}
int mid = t[p].l + t[p].r >> 1;
if(t[p].l <= x && x <= mid) change(p << 1, x, val);
if(mid + 1 <= x && x <= t[p].r) change(p << 1 | 1, x, val);
t[p].val = t[p << 1].val * t[p << 1 | 1].val % mod;
}
ll query(int p, int l, int r)
{
if(l <= t[p].l && t[p].r <= r) return t[p].val;
int mid = t[p].l + t[p].r >> 1;
ll ans = 1;
if(l <= mid) ans = ans * query(p << 1, l, r) % mod;
if(mid < r) ans = ans * query(p << 1 | 1, l, r) % mod;
return ans;
}
}Tree;
int main()
{
for (scanf ("%d", &t); t--; )
{
memset(a, 0, sizeof a);
scanf ("%d%lld", &n, &mod);
Tree.build(1, 1, n);
for (int i = 1; i <= n; i++)
{
int opt; ll m;
scanf ("%d%lld", &opt, &m);
m %= mod;
if(opt == 1) Tree.change(1, i, m);
else Tree.change (1, m, 1);
printf("%lld\n", Tree.query(1, 1, n));
}
}
return 0;
}