线段树简单使用 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
#include
#include
#include
#include
#include
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<

你可能感兴趣的:(算法)