穿梭时间的画面的钟 从反方向 开始移动|

tmjyh09

园龄:3年2个月粉丝:1关注:3

P4588 [TJOI2018]数学计算 题解

题目传送门

题意简述

x 初值为 1,要求支持以下操作:

操作 1:将 xxm,输出 xmodM

操作 2:将 xx÷kk 是第 m 次操作时乘上的数,输出 xmodM

分析

线段树好题!线段树好题!线段树好题!

做过这道题后,我真的对线段树有了更加深厚的了解。

看到这个题目其实很难想象可以使用线段树来做,但我们可以发现,如果我们按照时间轴,即 1Q 建一棵线段树,第 1 个数即为 x,一开始全部赋初值 1

i 个操作为 1 时就单点修改 im,这样 push_up时就可以将 xxm

为 2 时可以单点修改 i1,这样 push_up时,x 就相当于除以了 k(第 m 次操作乘上的数)。

每次查询,输出 tr[1].sum即可。

这样一分析,就变成了线段树裸题了(甚至还简单,都不用区间查询)。

代码实现

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=0;char ch=getchar();
while(!isdigit(ch))f^=!(ch^45),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
inline void write(int x){
if(x<0)x=-x,putchar('-');
if(x>=10)write(x/10);
putchar(x%10+'0');
}
inline void writeln(int x){write(x);puts("");}
int T,Q,mod;
struct segment{
int l,r,sum;
}tr[100005<<2];
inline int ls(int p){return p<<1;}
inline int rs(int p){return p<<1|1;}
inline void push_up(int p){tr[p].sum=(tr[ls(p)].sum*tr[rs(p)].sum)%mod;}
void build(int p,int l,int r){
tr[p]={l,r,1};
if(l==r)return;
int mid=l+r>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
push_up(p);
}
void update(int p,int x,int k){
if(tr[p].l==tr[p].r){
tr[p].sum=k;
return;
}
int mid=tr[p].l+tr[p].r>>1;
if(x<=mid)update(ls(p),x,k);
if(mid<x)update(rs(p),x,k);
push_up(p);
}
signed main(){
T=read();
while(T--){
Q=read();mod=read();
memset(tr,0,sizeof tr);
build(1,1,Q);
for(int i=1;i<=Q;i++){
int p=read(),m=read();
if(p==1)update(1,i,m),writeln(tr[1].sum%mod);
else update(1,m,1),writeln(tr[1].sum%mod);
}
}
#ifndef ONLINE_JUDGE
system("pause");
#endif
return 0;
}

本文作者:tmjyh09

本文链接:https://www.cnblogs.com/tmjyh09/p/15916280.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   tmjyh09  阅读(42)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起