Description
小豆现在有一个数x,初始值为1. 小豆有Q次操作,操作有两种类型:
1 m: x = x * m ,输出 x%mod;
2 pos: x = x / 第pos次操作所乘的数(保证第pos次操作一定为类型1,对于每一个类型1 的操作至多会被除一次),输出x%mod
一共有t组输入(t ≤ 5)
对于每一组输入,第一行是两个数字Q, mod(Q ≤ 100000, mod ≤ 1000000000);
接下来Q行,每一行为操作类型op,操作编号或所乘的数字m(保证所有的输入都是合法的).
1 ≤ Q ≤ 100000
Solution
这里需要注意mod不一定是质数,也就不一定有乘法逆元
考虑用线段树,操作一就在操作的位置插入m,操作二就是把第pos位贡献变为1,这样求区间乘积就可以了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int N=200005;
int wjp[N<<2],MOD;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void modify(int now,int tl,int tr,int x,int v) {
if (tl==tr) return (void) (wjp[now]=v);
int mid=(tl+tr)>>1;
if (x<=mid) modify(now<<1,tl,mid,x,v);
else modify(now<<1|1,mid+1,tr,x,v);
wjp[now]=1LL*wjp[now<<1]*wjp[now<<1|1]%MOD;
}
int query(int now,int tl,int tr,int l,int r) {
if (r<l) return 1;
if (tl>=l&&tr<=r) return wjp[now];
int mid=(tl+tr)>>1;
int qx=query(now<<1,tl,mid,l,std:: min(r,mid));
int qy=query(now<<1|1,mid+1,tr,std:: max(mid+1,l),r);
return 1LL*qx*qy%MOD;
}
void build(int now,int tl,int tr) {
wjp[now]=1;
if (tl==tr) return ;
int mid=(tl+tr)>>1;
build(now<<1,tl,mid);
build(now<<1|1,mid+1,tr);
}
int main(void) {
freopen("data.in","r",stdin);
for (int T=read();T--;) {
int n=read(); MOD=read();
build(1,1,n);
rep(i,1,n) {
int opt=read(),x=read();
if (opt==1) modify(1,1,n,i,x);
else modify(1,1,n,x,1);
printf("%d\n", wjp[1]);
}
}
return 0;
}