题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5475
思路:
这题直接模拟会出问题:因为他要求的只是输出结果取模。如果计算过程中取模,会导致x变化,令后续的操作得出的答案出现问题。
如果计算过程中不取模,会溢出。
所以我们考虑另一种方法:
对于每次操作,我们可以用一个数组将他的值存起来。如果是1操作,就令a[i]变为要乘的数y。如果是2操作,就令a[a[i]]变为1。
然后对每次询问,只要将1-i的数相乘取模即可得出答案。
这中间的操作可以利用线段树存取进行。
代码:
#include<stdio.h>
#include<string.h>
#define N 100005
#define ll __int64
struct tree{
ll l,r,sum;
}tree[N<<2];
ll M;
void build(ll l,ll r,ll root)
{
tree[root].l=l;
tree[root].r=r;
tree[root].sum=1;
ll mid=l+r>>1;
if(l==r)return;
build(l,mid,root<<1);
build(mid+1,r,root<<1|1);
}
void pushup(ll root)
{
if(tree[root].l==tree[root].r)return;
tree[root].sum=((tree[root<<1].sum%M)*(tree[root<<1|1].sum%M))%M;
}
void update(ll l,ll r,ll root,ll z)
{
if(l==tree[root].l&&r==tree[root].r)
{
tree[root].sum=z%M;
return ;
}
ll mid=tree[root].l+tree[root].r>>1;
if(r<=mid)update(l,r,root<<1,z);
else if(l>mid)update(l,r,root<<1|1,z);
else {
update(l,mid,root<<1,z);
update(mid+1,r,root<<1|1,z);
}
pushup(root);
}
ll query(ll l,ll r,ll root)
{
if(l==tree[root].l&&r==tree[root].r)
return tree[root].sum;
ll mid=tree[root].l+tree[root].r>>1;
if(r<=mid)return query(l,r,root<<1);
else if(l>mid)return query(l,r,root<<1|1);
else return query(l,mid,root<<1)%M*query(mid+1,r,root<<1|1)%M;
}
int main()
{
ll T,i,j,k,Q,x,y,a[100005];
scanf("%I64d",&T);
int t=0;
while(T--)
{
t++;
scanf("%I64d%I64d",&Q,&M);
build(1,Q,1);
printf("Case #%d:\n",t);
for(i=1;i<=Q;i++)
{
scanf("%I64d%I64d",&x,&a[i]);
if(x==1)
update(i,i,1,a[i]);
else if(x==2)update(a[i],a[i],1,1);
int ans=query(1,i,1);
printf("%I64d\n",ans%M);
}
}
return 0;
}