【线段树】数学计算

Description

小豆现在有一个数x,初始值为1. 小豆有Q次操作,操作有两种类型: 1 m: x = x * m ,输出 x%mod; 2 pos: x = x / 第pos次操作所乘的数(保证第pos次操作一定为类型1,对于每一个类型1 的操作至多会被除一次),输出x%mod

Input

一共有t组输入(t ≤ 5) 对于每一组输入,第一行是两个数字Q, mod(Q ≤ 100000, mod ≤ 1000000000); 接下来Q行,每一行为操作类型op,操作编号或所乘的数字m(保证所有的输入都是合法的). 1 ≤ Q ≤ 100000

Output

对于每一个操作,输出一行,包含操作执行后的x%mod的值

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

2
1
2
20
10
1
6
42
504
84

分析

比较简单的一道线段树了 我们建立一棵线段树,其叶子节点 i ii 保存的是第 i 次操作时乘的那个值 那么对于操作二,就是单点修改为1即可

代码

#include<bits/stdc++.h>
#define in read()
#define lson (rt<<1)
#define rson (rt<<1)|1
#define maxn 100009
#define ll long long
using namespace std;
int t,q,mod,m,caoz;
ll dis[maxn<<2];
void build(int rt,int l,int r){
    if(l==r){
        dis[rt]=1;
        return;
    }
    int mid=l+r>>1;
    build(lson,l,mid);build(rson,mid+1,r);
    dis[rt]=dis[lson]*dis[rson];
}
void insert(int rt,int l,int r,int now,ll x){
    if(l==r){
        dis[rt]=x%mod;return;
    }
    int mid=l+r>>1;
    if(now<=mid) 
        insert(lson,l,mid,now,x);
    else insert(rson,mid+1,r,now,x);
    dis[rt]=dis[lson]*dis[rson]%mod;
}
void change(int rt,int l,int r,int now,int x){
    if(l==r){
        dis[rt]=x;
        return;
    }
    int mid=l+r>>1;
    if(now<=mid) change(lson,l,mid,now,x);
    else change(rson,mid+1,r,now,x);
    dis[rt]=dis[lson]*dis[rson]%mod;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&q,&mod);
        int rt;
        build(1,1,q);
        for(int i=1;i<=q;++i){
            scanf("%d%d",&caoz,&m);
            if(caoz==1){
                printf("%d\n",dis[1]%mod*m%mod);
                insert(1,1,q,i,m);
            }
            else{
                change(1,1,q,m,1);
                printf("%d\n",dis[1]%mod);
            }
        }
    }
    return 0;
}

 

posted @ 2020-05-28 13:33  Vocanda  阅读(159)  评论(0编辑  收藏  举报