【BZOJ4768】wxh loves substring(后缀平衡树)

传送门


题解:

由于需要支持删除,所以SAM+LCT的做法不行了。

但是后缀平衡树就没有这个问题,注意删除和重构写得不好可能会炸精度。

没有删除的版本见:here


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int get_s(char *s){
		int len=0;char c;
		while(isspace(c=gc()));
		while(s[len++]=c,!isspace(c=gc())&&c!=EOF);
		return s[len]='\0',len;
	}
	
	template<typename T>
	inline T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=3e6+7;

char s[N];int sl;
char q[N];int ql;

namespace SGT{
	cs int N=8e5+7;
	int lc[N],rc[N],siz[N],*bad,rt;
	double L[N],R[N],rebl,rebr;
	
	cs double alpha=0.7;
	
	inline double val(int u){if(u==0)return -1e18;return L[u]+R[u];}
	inline bool Cmp(int u,int v){
		return s[u]<s[v]||(s[u]==s[v]&&val(u-1)<val(v-1));
	}
	
	inline void ins(int &u,int i,double l=0,double r=1e18){
		if(!u){u=i,siz[i]=1,lc[i]=rc[i]=0,L[i]=l,R[i]=r;return ;}
		++siz[u];double mid=(L[u]+R[u])*0.5;
		if(Cmp(u,i)){
			ins(rc[u],i,mid,r);
			if(siz[rc[u]]>siz[u]*alpha)bad=&u,rebl=l,rebr=r;
		}
		else {
			ins(lc[u],i,l,mid);
			if(siz[lc[u]]>siz[u]*alpha)bad=&u,rebl=l,rebr=r;
		}
	}
	inline int merge(int a,int b){
		if(!a||!b)return a|b;
		if(siz[a]>siz[b]){
			rc[a]=merge(rc[a],b);
			siz[a]=siz[lc[a]]+siz[rc[a]]+1;
			return a;
		}
		else {
			lc[b]=merge(a,lc[b]);
			siz[b]=siz[lc[b]]+siz[rc[b]]+1;
			return b;
		}
	}
	inline void del(int &u,int i,double l=0,double r=1e18){
		if(u==i){u=merge(lc[u],rc[u]);return ;}
		--siz[u];double mid=(L[u]+R[u])*0.5;
		if(val(u)<val(i)){
			del(rc[u],i,mid,r);
			if(siz[lc[u]]>siz[u]*alpha)bad=&u,rebl=l,rebr=r;
		}
		else {
			del(lc[u],i,l,mid);
			if(siz[rc[u]]>siz[u]*alpha)bad=&u,rebl=l,rebr=r;
		}
	}
	
	int q[N],qn;
	void inorder_dfs(int u){
		if(lc[u])inorder_dfs(lc[u]);q[++qn]=u;
		if(rc[u])inorder_dfs(rc[u]);
	}
	
	int build(int l,int r,double vl,double vr){
		if(l>r)return 0;
		int mid=l+r>>1;double Mid=(vl+vr)*0.5;
		int u=q[mid];L[u]=vl,R[u]=vr,siz[u]=r-l+1;
		lc[u]=build(l,mid-1,vl,Mid);
		rc[u]=build(mid+1,r,Mid,vr);
		return u;
	}
	
	inline void rebuild(int &u){
		qn=0;inorder_dfs(u);
		u=build(1,qn,rebl,rebr);
	}
	inline void Ins(int i){
		bad=NULL;ins(rt,i);
		if(bad!=NULL)rebuild(*bad);
	}
	inline void Del(int i){
		bad=NULL;del(rt,i);
		if(bad!=NULL)rebuild(*bad);
	}
	inline int Rank(char *q,int l){
		int u=rt,ans=0;
		while(u){
			int tp=0;
			for(int re j=0;j<=l;++j)
			if(q[j]!=s[u-j]){tp=q[j]>s[u-j];break;}
			if(tp)ans+=siz[lc[u]]+1;
			u=tp?rc[u]:lc[u];
		}
		return ans;
	}
}

int msk;
void decode(char *s,int l){
	for(int re j=0,tp=msk;j<l;++j)
	std::swap(s[j],s[tp=(tp*131+j)%l]);
}

int m;
signed main(){
#ifdef zxyoi
	freopen("substring.in","r",stdin);
#endif
	m=gi();sl=get_s(s+1);
	for(int re i=1;i<=sl;++i)SGT::Ins(i);
	while(m--){
		ql=get_s(q);
		switch(q[0]){
			case 'A':{
				ql=get_s(q+1);decode(q+1,ql);
				for(int re i=1;i<=ql;++i)
				s[sl+i]=q[i],SGT::Ins(sl+i);sl+=ql;
				break;
			}
			case 'D':{
				int l=gi();
				for(int re i=1;i<=l;++i)SGT::Del(sl--);
				break;
			}
			case 'Q':{
				ql=get_s(q);decode(q,ql);
				std::reverse(q,q+ql);
				int ans=-SGT::Rank(q,ql);
				q[ql]=127;ans+=SGT::Rank(q,ql);
				cout<<ans<<"\n";msk^=ans;
				break;
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值