题目传送门:http://acm.fzu.edu.cn/problem.php?pid=2297
题目:
Given a integers x = 1, you have to apply Q (Q ≤ 100000) operations: Multiply, Divide.
Input
First line of the input file contains an integer T(0 < T ≤ 10) that indicates how many cases of inputs are there.
The description of each case is given below:
The first line contains two integers Q and M. The next Q lines contains the operations in ith line following form:
M yi: x = x * yi.
N di: x = x / ydi.
It’s ensure that di is different. That means you can divide yi only once after yi came up.
0 < yi ≤ 109, M ≤ 109
Output
For each operation, print an integer (one per line) x % M.
Sample Input
1
10 1000000000
M 2
D 1
M 2
M 10
D 3
D 4
M 6
M 7
M 12
D 7
Sample Output
2
1
2
20
10
1
6
42
504
84
题意:给定一个整数x,x初始化为1,对x进行q次操作。操作共两种:乘yi和除ydi。要求是输出每次操作后x%m的值。
题解:把操作看成是点修改,输出结果看成区间查询的话,就可以用线段树来解决了。将线段树每个节点全部初始化为1,如下所示:
其中,每个父节点的值=左节点的值*右节点的值。根节点的值即x的值。进行第一个操作 M 2时,将编号1节点(M操作修改的是第i节点,i为操作数)的值修改为2。线段树如下所示:
进行第二个操作D 1 时,将编号1节点的值修改为1。修改后的线段树如下所示:
也就是说进行M yi操作时,将编号i节点的值修改为yi;进行D ydi操作时,将编号ydi节点的值修改为1。每次操作更新线段树,并输出根节点的值即可
代码及注释如下:
#include<iostream>
#define ll long long
using namespace std;
const int MAXN = 1e5 + 5;
ll m,sum[MAXN<<2];//MAXN<<2 等于 MAXN*4
void add_op(int t,int v,int l,int r,int rt) {
if(l==r) {//不可分节点
sum[rt] = v;
return ;
}
int mid = (l+r)>>1;
//(l+r)>>1 等于 (l+r)/2
//rt<<1 等于 rt*2
//rt<<1|1 等于 rt*2+1
if(t<=mid) add_op(t,v,l,mid,rt<<1);//左半区间
else add_op(t,v,mid+1,r,rt<<1|1);//右半区间
sum[rt] = sum[rt<<1] * sum[rt<<1|1] % m;//更新
}
int main() {
int T,n;
ios::sync_with_stdio(false);//加速
cin>>T;
while(T--) {
cin>>n>>m;
for(int i=1;i<=n<<2;i++) sum[i] = 1;//初始化为1
char op;
int tmp;
for(int i=1;i<=n;i++) {
cin>>op>>tmp;
if(op=='M') add_op(i,tmp,1,n,1);//节点i的值改为tmp
else add_op(tmp,1,1,n,1);//节点tmp的值改为1
cout<<sum[1]<<endl;//输出根节点的值
}
}
return 0;
}