和Leo一起做爱线段树的好孩子HDU5238 Calculator

版权声明:LeoJAM Presents https://blog.csdn.net/fcb_x/article/details/81980378

神仙题

感觉就是一个暴力啊

线段树维护的是一个类似于键值线段树的东西?

每个叶子节点才表示一个操作

而在PushUp的时候合并答案

这个咋合并?

暴力合并。我们记录下当前模意义下所有的答案

然后暴力合并

于是查答案是O1的

然后明显开不下空间

但是考虑到模数的特殊性

于是拆成小质数CRT一下就好了

很完美的把暴力+线段树合并的真实意义+数学结合起来的一道题

#include<bits/stdc++.h>
using namespace std;
#define lc (p<<1)
#define rc (p<<1|1)
const int N=50010;
int Mod[4]={7,13,17,19};
const int M=29393;
int n,m;
int P[4][20][M+1];
void Init(){
	for(int i=0;i<=3;i++){
		for(int j=0;j<Mod[i];j++){
			P[i][j][0]=1;
			for(int k=1;k<M;k++){
				P[i][j][k]=P[i][j][k-1]*j%Mod[i]; 
			}
		}
	}
}
struct Segment_Tree{
	int T[N<<2][4][20];
	inline void Clear(){
		memset(T,0,sizeof(T));
	}
	inline void PushUp(int p){
		for(int i=0;i<=3;i++){
			for(int j=0;j<Mod[i];j++)
			T[p][i][j]=T[rc][i][T[lc][i][j]];
		}
	}
	inline void PushNow(int p,char opt,int x){
		for(int i=0;i<=3;i++){
			for(int j=0;j<Mod[i];j++){
				if(opt=='+'){
					T[p][i][j]=(j+x)%Mod[i];
				}
				if(opt=='*'){
					T[p][i][j]=(j*x)%Mod[i];
				}
				if(opt=='^'){
					T[p][i][j]=P[i][j][x];
				}
			}
		}
	}
	inline void build(int p,int l,int r){
		if(l==r){
			char opt;
			int x;
			scanf("%c%d",&opt,&x);
//			cout<<opt<<" "<<x<<'\n';
			getchar();
			PushNow(p,opt,x);
			return;
		}
		int mid=(l+r)/2;
		build(lc,l,mid);
		build(rc,mid+1,r);
		PushUp(p);
	}
	inline void Update(int p,int l,int r,int pos,char opt,int x){
		if(l==r){
			PushNow(p,opt,x);
			return;
		}
		int mid=(l+r)/2;
		if(pos<=mid)Update(lc,l,mid,pos,opt,x);
		else Update(rc,mid+1,r,pos,opt,x);
		PushUp(p);
	}
}Tree;
int quick_pow(int x,int k,int Mod){
	int ret=1;
	while(k){
		if(k%2==1){
			ret=ret*x%Mod;
		}
		k/=2;
		x=x*x%Mod;
	}
	return ret;
}
void CRT(int x){
	int ans=0;
	for(int i=0;i<=3;i++){
		ans+=Tree.T[1][i][x%Mod[i]]*quick_pow(M/Mod[i],Mod[i]-2,Mod[i])%M*(M/Mod[i])%M; 
	}
	cout<<ans%M<<'\n';
}
void Solve(){
	scanf("%d%d",&n,&m);getchar();
	Tree.Clear();
	Tree.build(1,1,n);
	
	for(int i=1;i<=m;i++){
		int flag;
		scanf("%d",&flag);
//		cout<<i<<" "<<flag<<'\n';
		if(flag==1){
			int x;
			scanf("%d",&x);
			CRT(x);
//			cout<<"hello";
		}
		else{
			int x;
			int Id;
			char opt;
			scanf("%d",&Id);
			getchar();
			scanf("%c%d",&opt,&x);
			Tree.Update(1,1,n,Id,opt,x);
		}
	}
}
int main(){
//	freopen("test.in","r",stdin);
	int Cas,Id=0;
	Init();
	scanf("%d",&Cas);
	while(Cas--){
		cout<<"Case #"<<++Id<<":"<<'\n';
		Solve();
	}
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/81980378