题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5475
题目大意:给出一个数X,有两种操作:1 y表示将X乘上y,2 n表示将X除上第n个操作的y值(保证第n个操作存在且为1操作),给出Q次操作,输出每次操作之后的X%M的值。
分析:取模操作只是在输出X时才进行,运算时并不取模,故直接做显然是不行的(java大整数做的当我没说),考虑到有10^5次操作,我们可以以这些操作数为节点建立线段树,每个节点存放的是第i次操作:1操作可以表示为节点的值变为y,2操作可以将节点的值变为1,然后每次操作完后输出根结点的值,这样我们就把除法操作变为乘法操作了。
实现代码如下:
#include <cstdio> using namespace std; typedef long long ll; const int N=1e5+10; ll Q,M,x,op[N]; struct segment { int l,r; int mid() { return (l+r)>>1; } ll sum; }tree[N<<2]; void pushup(int rt) { tree[rt].sum=tree[rt<<1].sum*tree[rt<<1|1].sum%M; } void build(int rt,int l,int r) { tree[rt].l=l; tree[rt].r=r; if(l==r) { tree[rt].sum=1; return ; } int m=tree[rt].mid(); build(rt<<1,l,m); build(rt<<1|1,m+1,r); pushup(rt); } void update(int rt,int pos,int v) { if(tree[rt].l==pos&&tree[rt].r==pos) { tree[rt].sum=v%M; return ; } int m=tree[rt].mid(); if(pos<=m) update(rt<<1,pos,v); else update(rt<<1|1,pos,v); pushup(rt); } int main() { int t,T=1; scanf("%d",&t); while(t--) { scanf("%I64d%I64d",&Q,&M); build(1,1,Q); printf("Case #%d:\n",T++); for(int i=1;i<=Q;i++) { scanf("%I64d%I64d",&x,&op[i]); if(x==1) update(1,i,op[i]); else update(1,op[i],1); printf("%I64d\n",tree[1].sum); } } return 0; }