HDU-5475-An easy problem【线段树】

来源:互联网 发布:部落冲突11本升级数据 编辑:程序博客网 时间:2024/06/03 18:04

HDU-5475-An easy problem


Problem Description
One day, a useless calculator was being built by Kuros. Let’s assume that number X is showed on the screen of calculator. At first, X = 1. This calculator only supports two types of operation.
1. multiply X with a number.
2. divide X with a number which was multiplied before.
After each operation, please output the number X modulo M.

Input
The first line is an integer T(1 ≤ T ≤ 10), indicating the number of test cases.
For each test case, the first line are two integers Q and M. Q is the number of operations and M is described above. (1 ≤ Q ≤ 105,1 ≤ M ≤ 109)
The next Q lines, each line starts with an integer x indicating the type of operation.
if x is 1, an integer y is given, indicating the number to multiply. (0 < y ≤ 109)
if x is 2, an integer n is given. The calculator will divide the number which is multiplied in the nth operation. (the nth operation must be a type 1 operation.)

It’s guaranteed that in type 2 operation, there won’t be two same n.

Output
For each test case, the first line, please output “Case #x:” and x is the id of the test cases starting from 1.
Then Q lines follow, each line please output an answer showed by the calculator.

Sample Input
1
10 1000000000
1 2
2 1
1 2
1 10
2 3
2 4
1 6
1 7
1 12
2 7

Sample Output
Case #1:
2
1
2
20
10
1
6
42
504
84

题目链接:HDU-5475

题目大意:

两种操作:    1.输入 1 n, 表示 x 乘上一个数字x    2.输入 2 n, 表示 x 除以输入的第x个数字求每步操作结束x这个数字的值

题目思路:线段树,m个数字,求相当于m个结点的乘积。

初始化节点的值全部为1。

第一种操作:第i个节点的值改为n
第二种操作:第n个节点的值改为1

注意线段树中需要取模的地方。。。

以下是代码:

////  HH.cpp//  summer-1////  Created by pro on 2016/11/2.//  Copyright © 2016年 loy. All rights reserved.//#include <iostream>#include <iomanip>#include <fstream>#include <sstream>#include <cmath>#include <cstdio>#include <cstring>#include <cctype>#include <algorithm>#include <functional>#include <numeric>#include <string>#include <set>#include <map>#include <stack>#include <vector>#include <queue>#include <deque>#include <list>using namespace std;/* 一维线段树: 说明:    1. rt、L、R都是从1开始计数;    2. 线段树的空间应当是原数组的四倍;(最小应该为,向上取到最近的二的次幂,再乘以2)    3. 每次调用build,query和update时,L和R应该是整个区间(1-N),一般写成query(1,1,N)。 */#define lson rt<<1,L,M#define rson rt<<1|1,M+1,R#define maxn 100000 + 10long long mod;long long sumv[maxn<<2];void pushUp(int rt) {    sumv[rt] = (sumv[rt<<1] * sumv[rt<<1|1]) % mod;}void build(int rt, int L, int R) {    int M = (L+R) >> 1;    if (L == R) {        sumv[rt] = 1; //情况2,用build初始化线段树。    } else {        build(lson);        build(rson);        pushUp(rt);    }}//单点更新void update(int p, long long add, int rt, int L, int R, int flag) { //p代表要更新的点的位置    int M = (L+R) >> 1;    if (L == R) {        if (flag)        {            sumv[rt] = add % mod; //增加单节点值的例子,实际题目情况各种变化,v代表单点加的值        }        else            sumv[rt] = 1;    } else {        if (p <= M) update(p, add, lson, flag);        else update(p, add, rson, flag);        pushUp(rt);    }}long long query(int tl, int tr, int rt, int L, int R) {    int M = (L+R) >> 1;    long long ret = 0;    //if (lazy[rt]) pushDown(rt, R-L+1);     //如果需要更新(最底层)单个点的值    if (tl<=L && R<=tr) return sumv[rt] % mod; // 查询区间涵盖了整个区间    if (tl <= M) ret = (ret * query(tl, tr, lson)) % mod; // 查询区间在左边有分布    if (M < tr) ret = (query(tl, tr, rson) * ret) % mod; // 查询区间在右边有分布    return ret;}int main(){    int t;    scanf("%d",&t);    int cas = 1;    while(t--)    {        int n;        scanf("%d%lld",&n,&mod);        build(1,1,n);        printf("Case #%d:\n",cas++);        for (int i = 1; i <= n; i++)        {            long long f,b;            scanf("%lld%lld",&f,&b);            if (f == 1)            {                update(i, b, 1, 1, n, 1);            }            else            {                update(b, 0, 1, 1, n, 0);            }            long long res = query(1,n,1,1,n) % mod;            printf("%lld\n",res);        }    }}/* 1 10 1 1 2 2 1 1 2 1 10 2 3 2 4 1 6 1 7 1 12 2 7 */
0 0
原创粉丝点击