1. 程式人生 > >bzoj3682 Phorni 字尾平衡樹+線段樹

bzoj3682 Phorni 字尾平衡樹+線段樹

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