[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;
}