线段树简单使用 P4588 数学计算 总结

传送门icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P4588心路历程

一开始确实没想到能切换成线段树,毕竟它一无区间二无线段,我第一眼看到题以为是一个大大大模拟,但是这里不能用逆元(并不互质)

于是,运用一点思维,我们发现可以把一个区间全设成1(大小就是查询次数),每一次修改就修改那个点,第二种除法就将那个点化成1,这样维护一个区间,区间根节点的值就是答案

当然我一开并没马上反应过来根节点就是答案,还水了一个query函数查区间和,于是WA多次,最终发现:

(a*b)%P=(a%P*b%P)%P  (如果中间不%P可能会爆long long)

接下来附上代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<string>
#include<cmath>
using namespace std;
#define endl '\n'
#define lc p<<1
#define rc p<<1|1
int _;
const int N=1e5+10;
using ll=long long;
using ULL=unsigned long long;
#define int long long
int q,mod;
struct Tree{
	int l,r,sum;
}tr[N*4];
void pushup(int p){
	tr[p].sum=(tr[lc].sum*tr[rc].sum)%mod;
}
void build(int p,int l,int r){
	tr[p]={l,r,1};
	if(l==r) return;
	int m=(l+r)>>1;
	build(lc,l,m);
	build(rc,m+1,r);
	pushup(p);
}
void change(int p,int x,int k){
	if(tr[p].l==x&&tr[p].r==x){
		tr[p].sum=k;return;
	}
	int m=(tr[p].l+tr[p].r)>>1;
	if(x<=m) change(lc,x,k);
	if(x>m) change(rc,x,k);
	pushup(p);
}
ll query(int p,int l,int r){//白写了
	if(tr[p].l>=l&&tr[p].r<=r){
		return tr[p].sum%mod;
	}
	int m=(tr[p].l+tr[p].r)>>1;
	ll ans=1;
	if(l<=m) ans=(ans*(query(lc,l,r)))%mod;
	if(r>m) ans=(ans*(query(rc,l,r)))%mod;
	return ans%mod;
}

signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>_;
	while(_--){
        cin>>q>>mod;
        build(1,1,q);
        for(int i=1;i<=q;++i){
        	int op,m;
        	cin>>op>>m;
        	if(op==1) change(1,i,m),cout<<tr[1].sum<<endl;
        	else change(1,m,1),cout<<tr[1].sum<<endl;
        }
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值