BZOJ3331: [BeiJing2013]压力 图连通性
BZOJ1130: [POI2008]POD Subdivision of Kingdom 状压+dfs+恶心题

BZOJ3682: Phorni 后缀平衡树+线段树

shinbokuow posted @ Sep 08, 2015 08:28:48 PM in BZOJ with tags 后缀平衡树 线段树 , 2684 阅读

 

题解:

终于会写后缀平衡树了0.0

首先我们要知道Treap是什么东西。Treap是一种二叉平衡树,同时是重量平衡树,也即单次插入删除期望最大影响的子树大小为$O(logn)$。

也就是说,我们可以暴力重新计算该子树的信息而不用担心复杂度爆炸。

考虑利用重量平衡树来处理动态顺序维护问题。

现在有一个序列,你可以在序列中的某个位置插入一个元素,询问就是询问两个元素的先后顺序。

直接利用平衡树可以做到插入、询问均为$O(logn)$。

考虑动态标号法,在平衡树中的每个节点都记录$[l,r]$,这个节点的值为$\lfloor\frac{l+r}{2}\rfloor$。

如比较两个元素的顺序,只需要比较两个平衡树节点的值就行了,于是是$O(1)$。

现在要插入一个元素,在旋转之后树的形态可能会发生变化,好在最大影响的子树大小为$O(logn)$,所以直接暴力计算子树内的节点的值就行了,于是单次插入复杂度依然为$O(logn)$。

由于重量平衡树深度期望为$O(logn)$,所以需要的权值的值域在long long范围就可以保证完全区分了。

 

后缀平衡树就是维护后缀之间字典序从小到大的有序序列的平衡树。

假如对于字符串$S[1,n]$,已经构造好$S'[i,n]$的后缀平衡树,考虑如何构造$S''[i-1,n]$的后缀平衡树。

那么只需插入后缀$i-1$就行了。

那么在平衡树中进行插入时,就需要比较两个后缀的字典序大小咯。

而我们可以做到$O(1)$,原因在:若两个后缀首字母相同,则同时去掉首字母,转化为已经存在在平衡树中的两个后缀的顺序问题,利用动态标号就能做到$O(1)$询问;如果首字母不同则显然$O(1)$完成。

维护后缀平衡树实质上就是一个动态顺序维护问题,因此可以做到$O(nlogn)$构造,$O(1)$询问两个后缀的字典序大小,并支持在串的开头插入一个字符。

 

关于平衡树复杂度的证明有时间再说。

 

代码:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;

typedef unsigned long long llu;

#define N 1000010
#define ls ch[0]
#define rs ch[1]
struct Node{
	Node*ch[2];
	llu v;
	int ins,p;
}Tnull,*null=&Tnull,mem[N],*G=mem,*get[N],*root=null;
inline Node*newnode(int _ins){
	G->ls=G->rs=null;
	G->ins=_ins;
	G->p=rand();
	return G++;
}

typedef pair<int,int> pii;
inline pii Min(pii x,pii y){
	if(x.first==-1)
		return y;
	if(y.first==-1)
		return x;
	if(get[x.first]->v!=get[y.first]->v)
		return get[x.first]->v<get[y.first]->v?x:y;
	return x.second<y.second?x:y;
}

#define mp make_pair

#define inf ((llu(-1))>>1)
int p[500010];
struct SegmentTree{
	pii A[1048675];
	int M;
	inline void init(int _siz){
		for(M=1;M<(_siz+2);M<<=1);
		for(int i=0;i<(M<<1);++i)
			A[i]=mp(inf,0);
		for(int i=1;i<=_siz;++i)
			A[M+i]=mp(p[i],i);
		for(int i=M-1;i>=1;--i)
			A[i]=Min(A[i<<1],A[i<<1^1]);
	}
	inline void upd(int x,int _ins){
		for(A[x+=M].first=_ins,x>>=1;x;x>>=1)
			A[x]=Min(A[x<<1],A[x<<1^1]);
	}
	inline int query(int tl,int tr){
		pii ans=mp(-1,0);
		for(tl+=M-1,tr+=M+1;tl^tr^1;tl>>=1,tr>>=1){
			if(~tl&1)
				ans=Min(ans,A[tl^1]);
			if(tr&1)
				ans=Min(ans,A[tr^1]);
		}
		return ans.second;
	}
}Seg;

char s[N];
inline bool cmp(const int&x,const int&y){
	if(s[x]!=s[y])
		return s[x]>s[y];
	return get[x-1]->v>get[y-1]->v;
}

inline void rot(Node*&p,bool d){
	Node*q=p->ch[!d];
	p->ch[!d]=q->ch[d];
	q->ch[d]=p;
	p=q;
}
inline void recalc(Node*p,llu _l,llu _r){
	p->v=(_l+_r)>>1;
	if(p->ls!=null)
		recalc(p->ls,_l,(_l+_r)>>1);
	if(p->rs!=null)
		recalc(p->rs,1+((_l+_r)>>1),_r);
}

Node*lastp;
llu lastl,lastr;
inline void insert(Node*&p,int _ins,llu _l,llu _r){
	if(p==null){
		get[_ins]=p=newnode(_ins);
		p->v=(_l+_r)>>1;
		return;
	}
	bool d=cmp(_ins,p->ins);
	if(d==0){
		insert(p->ls,_ins,_l,(_l+_r)>>1);
		if(p->ls->p<p->p){
			rot(p,1);
			lastp=p;
			lastl=_l;
			lastr=_r;
		}
	}
	else{
		insert(p->rs,_ins,1+((_l+_r)>>1),_r);
		if(p->rs->p<p->p){
			rot(p,0);
			lastp=p;
			lastl=_l;
			lastr=_r;
		}
	}
}

/*inline void dfs(Node*p){
	if(p->ls!=null)
		dfs(p->ls);
	printf("%d ",p->ins);
	if(p->rs!=null)
		dfs(p->rs);
}*/

int main(){
#ifndef ONLINE_JUDGE
	freopen("tt.in","r",stdin);
	freopen("tt.out","w",stdout);
#endif
	int n,m,len,type;
	cin>>n>>m>>len>>type;
	int i;
	scanf("%s",s+1);
	for(i=1;i<=(len>>1);++i)
		swap(s[i],s[len-i+1]);
	for((get[0]=newnode(0))->v=0,i=1;i<=len;++i){
		lastp=null;
		insert(root,i,0,inf);
		if(lastp!=null)
			recalc(lastp,lastl,lastr);
	}
	
	//dfs(root);
	//puts("");

	for(i=1;i<=n;++i)
		scanf("%d",&p[i]);
	
	Seg.init(n);
	
	int lastans=0;
	
	char qte[10];
	int x,y;
	while(m--){
		scanf("%s",qte);
		if(qte[0]=='I'){
			scanf("%d",&x);
			if(type)
				x^=lastans;
			s[++len]='a'+x;
			lastp=null;
			insert(root,len,0,inf);
			if(lastp!=null)
				recalc(lastp,lastl,lastr);
		}
		else if(qte[0]=='C'){
			scanf("%d%d",&x,&y);
			Seg.upd(x,y);
		}
		else{
			scanf("%d%d",&x,&y);
			printf("%d\n",lastans=Seg.query(x,y));
		}
	}
	
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter