【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
", Tree.query(1, 1, n));
		}
	} 
	return 0;
}

原文地址:https://www.cnblogs.com/GJY-JURUO/p/14009412.html