【题解】[TJOI2018]数学计算

Problem

\(\text{Solution:}\)

首先发现模数不是质数,这意味着没有逆元可以让我们把除操作变成乘操作。而\(x\)本身又没有去取模,所以我们应该考虑维护一段连续区间的乘积。

那么删除操作就变成了将某个之前的节点删除。这对于 fhq_treap 是小意思了。

由于是一段有序的操作区间,所以我们可以按照 siz 分裂,维护区间乘积。

注意乘积的维护,左右孩子只有有的时候才乘,并且每次应该先让\(\text{mul[x]=val[x]}\)这样可以避免重复乘。

注意代码中的 getpos 函数,这里是从之前 书架 那题学来的套路:维护一个操作对应的树中编号,通过记录父亲以获得其与其左边的节点个数

这样我们就可以实现分裂操作了。维护乘积的细节和 getpos 函数的细节(加黑的地方是我忽略的地方)是收获所在。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
int tr[MAXN][2],cv[MAXN],val[MAXN],mul[MAXN],cnt,siz[MAXN],pa[MAXN];
int Q,M,rt,pos[MAXN];
inline int rd() {
	return rand()<<15|rand();
}
inline int md(int v) {
	val[++cnt]=v;
	cv[cnt]=rd();
	mul[cnt]=v;
	siz[cnt]=1;
	return cnt;
}
inline void pushup(int x) {
	siz[x]=siz[tr[x][0]]+siz[tr[x][1]]+1;
	mul[x]=val[x];
	if(tr[x][0])mul[x]=1ll*mul[x]*mul[tr[x][0]]%M;
	if(tr[x][1])mul[x]=1ll*mul[x]*mul[tr[x][1]]%M;
	if(tr[x][0])pa[tr[x][0]]=x;
	if(tr[x][1])pa[tr[x][1]]=x;
}
void split(int now,int k,int &x,int &y) {
	if(!now) {
		x=y=0;
		return;
	}
	if(k<=siz[tr[now][0]])y=now,split(tr[now][0],k,x,tr[now][0]);
	else x=now,split(tr[now][1],k-siz[tr[now][0]]-1,tr[now][1],y);
	pushup(now);
}
int merge(int x,int y) {
	if(!x||!y)return x+y;
	if(cv[x]<cv[y]) {
		tr[x][1]=merge(tr[x][1],y);
		pushup(x);
		return x;
	} else {
		tr[y][0]=merge(x,tr[y][0]);
		pushup(y);
		return y;
	}
}
int getpos(int x) {
	int res=siz[tr[x][0]]+1;
	while(pa[x]) {
		if(x==tr[pa[x]][1])res+=siz[tr[pa[x]][0]]+1;
		x=pa[x];
	}
	return res;
}
int T;
void del(int p){
	int u=getpos(p);
	int x,y,z;
	split(rt,u-1,x,z);
	split(z,1,y,z);
	y=merge(tr[y][0],tr[y][1]);
	rt=merge(merge(x,y),z);
	printf("%d\n",mul[rt]);
}
int main() {
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&Q,&M);
		int P=0;
		rt=merge(rt,md(1));
		pos[P]=cnt;
		while(Q--) {
			P++;
			int opt,g;
			scanf("%d%d",&opt,&g);
			if(opt==1) {
				rt=merge(rt,md(g));
				pos[P]=cnt;
				printf("%d\n",mul[rt]);
			} else {
				int node=pos[g];
				del(node);
			}
		}
		rt=0;
		for(int i=1;i<=cnt;++i)tr[i][1]=tr[i][0]=pa[i]=siz[i]=val[i]=mul[i]=cv[i]=0;
		for(int i=1;i<=P;++i)pos[i]=0;
		cnt=0;
	}
	return 0;
}
posted @ 2021-06-22 09:04  Refined_heart  阅读(50)  评论(0编辑  收藏  举报