传送门https://www.luogu.com.cn/problem/P4588心路历程
一开始确实没想到能切换成线段树,毕竟它一无区间二无线段,我第一眼看到题以为是一个大大大模拟,但是这里不能用逆元(并不互质)
于是,运用一点思维,我们发现可以把一个区间全设成1(大小就是查询次数),每一次修改就修改那个点,第二种除法就将那个点化成1,这样维护一个区间,区间根节点的值就是答案
当然我一开并没马上反应过来根节点就是答案,还水了一个query函数查区间和,于是WA多次,最终发现:
(a*b)%P=(a%P*b%P)%P (如果中间不%P可能会爆long long)
接下来附上代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<cmath>
using namespace std;
#define endl '\n'
#define lc p<<1
#define rc p<<1|1
int _;
const int N=1e5+10;
using ll=long long;
using ULL=unsigned long long;
#define int long long
int q,mod;
struct Tree{
int l,r,sum;
}tr[N*4];
void pushup(int p){
tr[p].sum=(tr[lc].sum*tr[rc].sum)%mod;
}
void build(int p,int l,int r){
tr[p]={l,r,1};
if(l==r) return;
int m=(l+r)>>1;
build(lc,l,m);
build(rc,m+1,r);
pushup(p);
}
void change(int p,int x,int k){
if(tr[p].l==x&&tr[p].r==x){
tr[p].sum=k;return;
}
int m=(tr[p].l+tr[p].r)>>1;
if(x<=m) change(lc,x,k);
if(x>m) change(rc,x,k);
pushup(p);
}
ll query(int p,int l,int r){//白写了
if(tr[p].l>=l&&tr[p].r<=r){
return tr[p].sum%mod;
}
int m=(tr[p].l+tr[p].r)>>1;
ll ans=1;
if(l<=m) ans=(ans*(query(lc,l,r)))%mod;
if(r>m) ans=(ans*(query(rc,l,r)))%mod;
return ans%mod;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>_;
while(_--){
cin>>q>>mod;
build(1,1,q);
for(int i=1;i<=q;++i){
int op,m;
cin>>op>>m;
if(op==1) change(1,i,m),cout<<tr[1].sum<<endl;
else change(1,m,1),cout<<tr[1].sum<<endl;
}
}
return 0;
}