题目描述
小豆现在有一个数 x,初始值为
1。小豆有 Q 次操作,操作有两种类型:
1 m:将 x 变为 ×*m,并输出 xmodM。
2 pos:将 x 变为 x 除以第 pos 次操作所乘的数(保证第 pos 次操作一定为类型 1,对于每一个类型 1 的操作至多会被除一次),并输出 xmodM。
输入格式
一共有 t 组输入。对于每一组输入,第一行是两个数字,Q,M。接下来 Q 行,每一行为操作类型 op,操作编号或所乘的数字 m(保证所有的输入都是合法的)。
输出格式
对于每一个操作,输出一行,包含操作执行后的 xmodM 的值。
题目分析
将每次操作当成一个叶子节点,用线段树来维护区间积。
先建树,先将所有的叶子节点初始化为1,在每次的操作1中,将叶子节点值改为m,并pushup一下(向上更新区间积)
在每次的操作2中,将叶子节点重新改为1,并进行pushup操作一次。
代码演示
`#include
include
include
include<bits/stdc++.h>
using namespace std;
define ll long long
define N 200020
define ls u<<1
define rs u<<1|1
int d;
struct tree
{
int l,r;
ll mx;
}tr[N4];
void pushup(int u)
{
tr[u].mx=tr[ls].mxtr[rs].mx%d;
return ;
}
void build(int u,int l,int r)
{
tr[u]={l,r,1};
if(lr)
{
return ;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
void change(int x,int u,int y)
{
if(tr[u].lx&&tr[u].r==x)
{
tr[u].mx=y%d;
return ;
}
int m=tr[u].l+tr[u].r>>1;
if(x<=m)
change(x,ls,y);
else
change(x,rs,y);
pushup(u);
}
int query(int u,int l,int r)
{
if(l<=tr[u].l&&tr[u].r<=r)
return tr[u].mx%d;
int m=tr[u].l+tr[u].r>>1;
int ans=1;
if(l<=m) ans=query(ls,l,r)%d;
if(r>m) ans=ans*query(rs,l,r)%d;
return ans%d;
}
int main()
{
cin.tie(NULL);
cout.tie(nullptr);
ios_base::sync_with_stdio(false);
int q,m;
int n=0;
int c,y;
int t;
cin>>t;
while(t--)
{
cin>>m>>d;
build(1,1,m);
for(int i=1;i<=m;i++)
{
cin>>c>>y;
if(c==1)
{
change(i,1,y);
cout<<query(1,1,m)%d<<'\n';
}
else {
change(y,1,1);
cout<<query(1,1,m)%d<<'\n';
//cout<<t<<"\n";
}
}
}
return 0;
}`
请注意:思路来自董晓算法,哔哩哔哩搜索董晓算法。