【校内模拟】幻想(后缀平衡树)

简要题意:

给你一个字符串 S S S,请你支持:

  1. 末尾加字符
  2. 末尾删字符
  3. 给一个询问串 Q Q Q ,求 Q Q Q S [ l : r ] S[l:r] S[l:r] 中出现了多少次。

强制在线


题解:

如果第三个操作没有 l , r l,r l,r 的限制就是 BZOJ4768,后缀平衡树裸题。

有的话也没什么区别,开个vector维护一下子树内的点有哪些就行了。

复杂度好像是两个 log,但是跑得飞起。


代码:

#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++;
}template<typename T>T get_integer(){
	char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
	while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}

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;
}

}using namespace IO;

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

cs int N=2e5+7;

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


int lc[N],rc[N],sz[N],*bad,rt;
double L[N],R[N],rebl,rebr;
std::vector<int> nd[N];

cs double alpha=0.75;

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));
}

void ins(int &u,int i,double l=0,double r=1e18){
	if(!u){
		u=i,sz[i]=1;
		lc[u]=rc[u]=0;
		L[i]=l,R[i]=r;
		nd[i].clear();
		nd[i].push_back(i);
		return ;
	}++sz[u];nd[u].push_back(i);
	double M=(L[u]+R[u])/2;
	if(Cmp(u,i)){
		ins(rc[u],i,M,r);
		if(sz[rc[u]]>sz[u]*alpha)
			bad=&u,rebl=l,rebr=r;
	}else {
		ins(lc[u],i,l,M);
		if(sz[lc[u]]>sz[u]*alpha)
			bad=&u,rebl=l,rebr=r;
	}
}

void merge(std::vector<int> &res,cs std::vector<int> &b){
	cs std::vector<int> a=res;res.resize(a.size()+b.size());
	std::merge(a.begin(),a.end(),b.begin(),b.end(),res.begin());
}

int merge(int a,int b){
	if(!a||!b)return a|b;
	if(sz[a]>sz[b]){
		merge(nd[a],nd[b]);
		rc[a]=merge(rc[a],b);
		sz[a]=sz[lc[a]]+sz[rc[a]]+1;
		return a;
	}else {
		merge(nd[b],nd[a]);
		lc[b]=merge(a,lc[b]);
		sz[b]=sz[lc[b]]+sz[rc[b]]+1;
		return b;
	}
}

void del(int &u,int i,double l=0,double r=1e18){
	if(u==i){
		u=merge(lc[u],rc[u]);
		return ;
	}--sz[u];
	nd[u].pop_back();
	double M=(L[u]+R[u])/2;
	if(val(u)<val(i)){
		del(rc[u],i,M,r);
		if(sz[lc[u]]>sz[u]*alpha)
			bad=&u,rebl=l,rebr=r;
	}else {
		del(lc[u],i,l,M);
		if(sz[rc[u]]>sz[u]*alpha)
			bad=&u,rebl=l,rebr=r;
	}
}

int Q[N],qn;
void ino_dfs(int u){
	if(lc[u])ino_dfs(lc[u]);
	Q[++qn]=u;
	if(rc[u])ino_dfs(rc[u]);
}

int build(int l,int r,double vl,double vr){
	if(l>r)return 0;
	int mid=(l+r)>>1;double vm=(vl+vr)/2;
	int u=Q[mid];L[u]=vl,R[u]=vr,sz[u]=r-l+1;
	lc[u]=build(l,mid-1,vl,vm);
	rc[u]=build(mid+1,r,vm,vr);
	nd[u].clear();nd[u].push_back(u);
	merge(nd[u],nd[lc[u]]);merge(nd[u],nd[rc[u]]);
	return u;
}

void rebuild(int &u){
	qn=0;ino_dfs(u);
	u=build(1,qn,rebl,rebr);
}

void Ins(int i){
	bad=nullptr;ins(rt,i);
	if(bad!=nullptr)
		rebuild(*bad);
}

void Del(int i){
	bad=nullptr;del(rt,i);
	if(bad!=nullptr)
		rebuild(*bad);
}

int query(cs std::vector<int> &nd,int l,int r){
	return std::upper_bound(nd.begin(),nd.end(),r)
		-std::lower_bound(nd.begin(),nd.end(),l);
}

int Rank(int l,int r){
	int u=rt,ans=0;
	while(u){
		int tp=0;
		for(int re j=0;j<=ql;++j)
			if(q[j]!=s[u-j]){
				tp=q[j]>s[u-j];
				break;
			}
		if(tp)ans+=query(nd[lc[u]],l,r)+(l<=u&&u<=r);
		u=tp?rc[u]:lc[u];
	}return ans;
}

int las;

inline int toid(char c){
	return islower(c)?c-'a':26+c-'A';
}

inline char toch(int id){
	return id>25?id-26+'A':id+'a';
}

void decode(){
	for(int re i=0;i<ql;++i)
		q[i]=toch((toid(q[i])+las)%52);
}

void Main(){
	sl=get_s(s+1);
	for(int re i=1;i<=sl;++i)Ins(i);
	int Q=gi();
	while(Q--)switch(gi()){
		case 1:{
			ql=get_s(q);
			decode();
			s[++sl]=q[0];
			Ins(sl);
			break;
		}case 2:{
			Del(sl--); 
			break;
		}case 3:{
			int l=gi(),r=gi();ql=get_s(q);
			decode();l^=las,r^=las;
			std::reverse(q,q+ql);
			if(r-l+1<ql)cout<<(las=0)<<"\n";
			else {
				l+=ql-1;
				int ans=-Rank(l,r);
				q[ql]=127;ans+=Rank(l,r);
				cout<<(las=ans)<<"\n";
			}
			break;
		}
	}
}

inline void file(){
#ifdef zxyoi
	freopen("fantasy.in","r",stdin);
#else
	freopen("fantasy.in","r",stdin);
	freopen("fantasy.out","w",stdout);
#endif
}signed main(){file();Main();return 0;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值