bzoj3682 Phorni 后缀平衡树+线段树

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/85797736

Description


给定一个字符串和n个pos,要求资瓷:

  1. 开头插入一个字符c
  2. 将第x个pos改为y
  3. 查询第l到r个pos中所代表的最大后缀
    强制在线

Solution


久违的串串题。感觉后缀平衡树好像挺好写的,在线还能logn。

由于强制在线我们不能用SA,因为只存在前端插入因此考虑新增后缀的排名怎么维护。

比较两个后缀等价于分别比较首字母和下一位后缀的rank,由于这四个东西都是已知的因此比较就是O(1)的了。

我们可以把rank映射来维护后缀排名的相对大小,也正是因为这样我们才需要用一种重量平衡的平衡树来维护SA序列。这里写treap旋转的时候暴力修改,或者替罪羊暴力重构都是可以的,感觉替罪羊树要科学一些( ╯□╰ )
快速求出了rank之后就是简单的线段树上问题了

一开始挂了很多次是因为随机数值域没开够,太菜了orz

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const LL INF=(1LL<<61);
const int N=1000005;

struct treeNode {
	int son[2],fa,pri;
	LL L,R,rnk;
} t[N];

int mn[N<<2],pos[N],root;

char str[N];

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void build(int x) {
	LL mid=(t[x].L+t[x].R)/2;
	t[x].rnk=mid;
	if (t[x].son[0]) {
		t[t[x].son[0]].L=t[x].L;
		t[t[x].son[0]].R=mid-1;
		build(t[x].son[0]);
	}
	if (t[x].son[1]) {
		t[t[x].son[1]].L=mid+1;
		t[t[x].son[1]].R=t[x].R;
		build(t[x].son[1]);
	}
}

void rotate(int x) {
	int y=t[x].fa; int z=t[y].fa;
	int k=t[y].son[1]==x;
	t[y].son[k]=t[x].son[!k]; t[t[x].son[!k]].fa=y;
	t[y].fa=x; t[x].son[!k]=y;
	t[x].fa=z; t[z].son[t[z].son[1]==y]=x;
	t[x].L=t[y].L; t[x].R=t[y].R;
	build(x);
}

bool les(int x,int y) {
	return (str[x]==str[y])?(t[x-1].rnk<=t[y-1].rnk):(str[x]<str[y]);
}

void ins(int x,int nw) {
	int k=les(x,nw);
	if (!t[x].son[k]) {
		t[x].son[k]=nw;
		t[nw].pri=rand()*rand();
		t[nw].fa=x;
		LL mid=(t[x].L+t[x].R)/2;
		if (!k) t[nw].L=t[x].L,t[nw].R=mid-1;
		else t[nw].L=mid+1,t[nw].R=t[x].R;
		t[nw].rnk=(t[nw].L+t[nw].R)>>1;
	} else ins(t[x].son[k],nw);
	if (t[t[x].son[k]].pri>t[x].pri) {
		if (x==root) root=t[x].son[k];
		rotate(t[x].son[k]);
	}
}

void modify(int now,int tl,int tr,int x) {
	if (tl==tr) return (void) (mn[now]=x);
	int mid=(tl+tr)>>1;
	if (x<=mid) modify(now<<1,tl,mid,x);
	else modify(now<<1|1,mid+1,tr,x);
	if (les(pos[mn[now<<1]],pos[mn[now<<1|1]])) mn[now]=mn[now<<1];
	else mn[now]=mn[now<<1|1];
}

int query(int now,int tl,int tr,int l,int r) {
	if (r<l) return 0;
	if (tl>=l&&tr<=r) return mn[now];
	int mid=(tl+tr)>>1;
	int qx=query(now<<1,tl,mid,l,std:: min(r,mid));
	int qy=query(now<<1|1,mid+1,tr,std:: max(mid+1,l),r);
	if (qx*qy==0) return qx+qy;
	return (les(pos[qx],pos[qy]))?(qx):(qy);
}

int main(void) {
	srand(20020303);
	freopen("data.in","r",stdin);
	freopen("myp.out","w",stdout);
	int n=read(),m=read(),len=read(),type=read();
	scanf("%s",str+1); str[0]=-1;
	rep(i,1,len/2) std:: swap(str[i],str[len-i+1]);
	root=1; t[1].L=0,t[1].R=INF; t[1].rnk=INF/2; t[1].pri=rand()*rand();
	rep(i,2,len) ins(root,i);
	rep(i,1,n) {
		pos[i]=read();
		modify(1,1,n,i);
	}
	for (int lastans=0,ch;m--;) {
		for (ch=getchar();ch!='Q'&&ch!='I'&&ch!='C';ch=getchar());
		if (ch=='I') {
			int x=read()^(type*lastans);
			str[++len]=x+'a';
			ins(root,len);
		} else if (ch=='C') {
			int x=read(); pos[x]=read();
			modify(1,1,n,x);
		} else {
			int l=read(),r=read();
			printf("%d\n", lastans=query(1,1,n,l,r));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/85797736