第九届福建省大学生程序设计竞赛 FZU 2297 Number theory(题解+代码)

题目传送门:http://acm.fzu.edu.cn/problem.php?pid=2297
题目:

Number theory
Problem Description

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,如下所示:
题解图片1
其中,每个父节点的值=左节点的值*右节点的值。根节点的值即x的值。进行第一个操作 M 2时,将编号1节点(M操作修改的是第i节点,i为操作数)的值修改为2。线段树如下所示:
题解图片2
进行第二个操作D 1 时,将编号1节点的值修改为1。修改后的线段树如下所示:
题解图片3
也就是说进行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;
}

ac图片

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值