这题咋一看不就是开long long然后模拟吗? 但是模拟的话,如果出现连续Q/2次乘,然后连续Q/2次除以,就只能留到最后取模(否则除的时候就出错了),这样是会爆long long 的。所以不能单纯模拟
我们换个思路,如果我们把输入序列记录下来,每次改一个数就从新算一遍。
这不就相当于点修改,区间乘积查询吗? 很明显可以用线段树维护,让"从新算一遍"降到log级别复杂度。
我们建一棵Q个叶子节点的线段树维护区间乘积,叶子节点初始化成1。
用a[ ]记录输入的数。
如果第i次操作是操作1 就把第i个叶子节点改成a[i]
如果第i次操作是操作2 就把区间是a[i]的叶子节点改成1
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5+7;
const int INF =0x3f3f3f3f;
//线段树维护单点修改 区间乘积
//建一棵有Q个叶子节点的线段树[1,Q] 每个叶子都是1 非叶子节点维护区间乘积
ll tree[maxn*4];
int q,f,m;
int a[maxn];
inline int lc(int &rt)
{
return rt<<1;
}
inline int rc(int &rt)
{
return rt<<1|1;
}
inline void pushup(int &rt)
{
tree[rt]=tree[lc(rt)]*tree[rc(rt)]%m;
}
inline void updata_p(int rt,int l,int r,int index,int v)//单点修改
{
if(index<l || index>r) return;
if(l == r && r==index)
{
tree[rt]=v;
return ;
}
int mid=(l+r)>>1;
updata_p(lc(rt),l,mid,index,v);
updata_p(rc(rt),mid+1,r,index,v);
//修改后pushup操作就以log的时间复杂度从新计算了一遍答案
pushup(rt);
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d %d",&q,&m);
fill(tree,tree+maxn*4,1);
for(int i=1;i<=q;i++)
{
scanf("%d %d",&f,a+i);
if(f == 1)
{
updata_p(1,1,q,i,a[i]);
printf("%lld\n",tree[1]);
}
else
{
updata_p(1,1,q,a[i],1);
printf("%lld\n",tree[1]);
}
}
}
return 0;
}