题意:
每次给定两种操作中的一种
操作1:乘上x 然后%mod 输出
操作2:除以第x次操作乘的那个数,输出mod
思路:
由于模的存在,不能直接除以之前乘的那个数,暴力能水过,我们考虑线段树
线段树记录区间乘积
对于每个点i(对应于第i次操作),如果是乘法,就把该点更新成x,如果是除法,就更新成1,这样就相当于没成。然后查询区间乘积,区间是1~当前的i,其实也可以直接输出根节点的值,因为后面没涉及到的在建树时初始化成了1.
#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+5;
int mod;
struct node{
int l,r;
ll val;
}tree[maxn<<2];
void pushup(int m)
{
tree[m].val=tree[m<<1].val*tree[m<<1|1].val%mod;
}
/*void pushdown(int m)
{
if(tree[m].lazy)
{
tree[m<<1].lazy+=tree[m].lazy;
tree[m<<1|1].lazy+=tree[m].lazy;
tree[m<<1].val+=(tree[m<<1].r-tree[m<<1].l+1)*tree[m].lazy;
tree[m<<1|1].val+=(tree[m<<1|1].r-tree[m<<1|1].l+1)*tree[m].lazy;
tree[m].lazy=0;
}
}*/
void build(int m,int l,int r)
{
tree[m].l=l;
tree[m].r=r;
if(l==r)
{
tree[m].val=1;
return ;
}
int mid=(l+r)>>1;
build(m<<1,l,mid);
build(m<<1|1,mid+1,r);
pushup(m);
}
void update(int m,int index,int val)
{
if(tree[m].l==index&&tree[m].r==index)
{
tree[m].val=val;
return;
}
int mid=(tree[m].l+tree[m].r)>>1;
if(index<=mid)
update(m<<1,index,val);
else
update(m<<1|1,index,val);
pushup(m);
}
/*void query(int m,int l,int r)
{
if(tree2[m].l==l&&tree2[m].r==r)
{
minn=min(tree2[m].val,minn);
return;
}
int mid=(tree2[m].l+tree2[m].r)>>1;
if(r<=mid)
querymin(m<<1,l,r);
else if(l>mid)
querymin(m<<1|1,l,r);
else
querymin(m<<1,l,mid),querymin(m<<1|1,mid+1,r);
}*/
int main()
{
int n,q,t,ok=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&q,&mod);
build(1,1,q);
printf("Case #%d:\n",ok++);
for(int i=1;i<=q;i++)
{
int op;
ll x;
scanf("%d%lld",&op,&x);
if(op==1)
update(1,i,x);
else
update(1,x,1);
printf("%lld\n",tree[1].val);
}
}
return 0;
}