线段树 + 乘法+取模
题意:
有一个数字最开始是1,现在有两种操作,1. 乘以一个数字y,取模输出答案2. 除以一个之前乘以的数字,取模输出答案。
思路:
操作次数有1e5个,直接乘法也有可能,但是问题是一些数字乘了又除了,直接写很容易由于精度的问题爆了。而线段树竟然可以这样解决!!!线段树维护所有操作,核心操作是乘法,当除以一个数字时,就把那个数字改为1,然后轻轻松松根据回溯就可以不超精度解决,并且让x没必要一直保持一个很大的状态,线段树每次重新利用到没有修改的结果进行修改即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 1e5;
struct Tree
{
int l,r;
LL mul;
}rt[maxn*4];
int n;
int mod;
void build(int root,int l,int r)
{
rt[root].l = l,rt[root].r = r;
rt[root].mul = 1;
if(l == r) return ;
int mid = (l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
return ;
}
void push_up(int root)
{
rt[root].mul = (rt[root<<1].mul*rt[root<<1|1].mul)%mod;
}
void update(int root,int l,int r,int c)
{
if(rt[root].l > r || rt[root].r < l) return ;
if(rt[root].l >= l && rt[root].r <= r) {
rt[root].mul = c;
return ;
}
update(root<<1,l,r,c);
update(root<<1|1,l,r,c);
push_up(root);
}
int main()
{
//freopen("in.txt","r",stdin);
int t,ncase = 1;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&mod);
build(1,1,n);
printf("Case #%d:\n",ncase++);
for(int i = 1;i <= n; i++) {
int op ;
scanf("%d",&op);
if(op == 1) {
int y;
scanf("%d",&y);
update(1,i,i,y);
printf("%I64d\n",rt[1].mul);
}
else {
int ith;
scanf("%d",&ith);
update(1,ith,ith,1);
printf("%I64d\n",rt[1].mul);
}
}
}
return 0;
}