P4588 [TJOI2018]数学计算 题解

P4588 [TJOI2018]数学计算

Solve

这道题初看没什么想法,然后想到每次去除一个以前出现过的数也许就等于撤销操作,然后每次只改动一个数,线段树就可以很好的完成这个效果,然后就是一个水题了,代码实现起来也不难

拿时间为线建一颗线段树,然后每次修改第(i)号位置上的值,最后求和的时候取树根就好了

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=100005;
LL c[maxn<<2],Mod,Q,lst[maxn];
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
void pushup(int x){
	c[x]=c[x<<1]*c[x<<1|1]%Mod;
}
void Build(int x,int L,int R){
	if(L==R){c[x]=1;return;}
	int mid=(R-L>>1)+L;
	Build(x<<1,L,mid);Build(x<<1|1,mid+1,R);
	pushup(x);
	return ;
}
void change(int x,int L,int R,int pos,LL val){
	if(L==R){c[x]=val;return;}
	int mid=(R-L>>1)+L;
	if(pos<=mid)change(x<<1,L,mid,pos,val);
	else change(x<<1|1,mid+1,R,pos,val);
	pushup(x);
	return ;
}
int main(){
	freopen("P4588.in","r",stdin);
	freopen("P4588.out","w",stdout);
	int P=read();
	while(P--){
		Q=read(),Mod=read();
		Build(1,1,Q);
		for(int i=1;i<=Q;i++){
			int T=read();
			if(T==1){
				LL v=lst[i]=read();
				change(1,1,Q,i,v);
			}
			else{
				LL v=read();
				change(1,1,Q,v,1);
			}
			printf("%d
",c[1]);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/15140325.html