[TJOI2018]数学计算

[TJOI2018]数学计算

洛谷题目链接


题解

这道题有很多做法,可以求逆元,高精,不过用线段树会简单很多,首先我们要求得一个乘积,并且需要步步取模,我们用线段树维护乘积,建一颗大小为询问次数的线段树,每一个叶子节点存储每一次询问的数,初始化为\(1\),一号节点即为当前的乘积,每次对于操作\(1\),进行单点修改,对于操作\(2\),将\(pos\)位上的叶子修改为\(1\),,每次输出1节点,并取模即可。需要注意的是,线段树子节点信息给父节点时需要取模。

代码

#include<bits/stdc++.h>
using namespace std;
const int MN=1e5+100;
#define int long long
int T;
int q,m;
struct tree{
	int l,r,sum;
}t[MN<<2];
#define lc id<<1
#define rc id<<1|1
void pushup(int id){
	t[id].sum=(t[lc].sum*t[rc].sum)%m;
}
void build(int id,int l,int r){
	t[id].l=l,t[id].r=r;
	if(l==r){
		t[id].sum=1;
		return;
	}
	int mid=(l+r)>>1;
	build(lc,l,mid),build(rc,mid+1,r);
	pushup(id);
}
void update(int id,int pos,int val){
	if(t[id].l==t[id].r){
		t[id].sum=val;
		return;
	}
	int mid=(t[id].l+t[id].r)>>1;
	if(pos<=mid)update(lc,pos,val);
	else update(rc,pos,val);
	pushup(id);
}
signed main(){
	//freopen("cal.in","r",stdin);
	//freopen("cal.out","w",stdout);
	scanf("%d",&T);
	while(T--){
		scanf("%lld%lld",&q,&m);
		build(1,1,q);
		for(int i=1,op,x;i<=q;++i){
			scanf("%lld%lld",&op,&x);
			if(op==1)update(1,i,x),printf("%lld\n",t[1].sum%m);
			else update(1,x,1),printf("%lld\n",t[1].sum%m);
		}
	}
	return 0;
}
posted @ 2021-08-15 15:05  fanner_rick  阅读(68)  评论(0)    收藏  举报