字尾平衡樹,就是動態的維護字尾陣列,可以 \(o(\log n)\) 在末尾插入字元,\(o(\log n)\) 查詢 \(rank,sa\)。但是由於是維護的字尾資訊,所以插入只能在末尾插入字元(然後轉化成在開頭加乙個字元),相當於新增乙個字尾。
方法一:
我們需要一種能比較兩個字尾大小的方法,最簡單就是二分+hash,\(o(\log n)\) 實現,再加上平衡樹插入複雜度,總複雜度 \(o(\log^2 n)\)。
方法二:
考慮另一種比較方法,因為每次只新增乙個字元,也就是說如果把第乙個字元刪掉,那剩下的字串在之前已經插入過字尾平衡樹中了,我們只需要先比較一下兩個字尾的第乙個字元,後面字串的比較直接呼叫之前資訊就好。
那怎麼快速比較字尾平衡樹中兩個字尾大小呢?我們給每個點乙個權值區間 \([l,r]\),定義這個點的權值 \(tag_i\) 為 \(mid=\frac2\)。那它左子樹對應的區間就是 \([l,mid-1]\),右子樹對應的區間就是 \([mid+1,r]\)。發現如果按照中序遍歷的順序遍歷整顆平衡樹,那每個點的權值是單調遞增的。
可是這是平衡樹誒。如果是那種基於旋轉重構的平衡樹那豈不是每次旋轉都要重構一遍子樹內的權值? \(emmm\) 確實是這樣,所以要用到一種更高階的平衡樹---重量平衡樹。重量平衡樹就是要保證平衡不能是均攤平衡,然後要麼沒有旋轉,要麼旋轉影響的子樹大小是期望\(\log\)或者均攤\(\log\)。\(treap\) 和替罪羊樹都滿足這個條件。所以我們直接拿 \(treap\) 維護就好了。
嗯以上就是基本概念了,然後講一下怎麼維護好我們需要的 \(rank,sa,height\) 陣列。
再次強調這裡把每次往末尾插入乙個元素轉化成每次往開頭插入乙個元素
回顧最開始說的比較方法,如果兩個字串首字元不一樣那麼直接比較,否則比較去掉首字元後兩個字串的 \(tag\) 值。**長這樣:
bool cmp(int x,int y) else
}
同時因為我們需要二分+雜湊維護 \(height\),所以還需要動態維護雜湊值。
別的就沒啥了。
也不知道有啥用。
一道例題 要求往字串末尾插入乙個字元,撤銷乙個插入,詢問當前字串本質不同子串個數。
#pragma gcc optimize(2)
#includeusing std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
#define pb(a) push_back(a)
#define pii std::pair#define all(a) a.begin(),a.end()
#define mp(a,b) std::make_pair(a,b)
#define int long long
const int n=1e5+5;
const int inf=1e18;
const int base=9973;
char s[n];
int lcp[n],ans,prio[n];
int root,tag[n],ch[n][2];
int n,tot,sze[n];;ull hsh[n],pw[n];
int getint()
bool cmp(int x,int y)
void rotate(int &x,int d,int l,int r)
void insert(int &x,int l,int r) int d=cmp(x,tot),mid=l+r>>1;
sze[x]++;
if(d) insert(ch[x][d],mid+1,r);
else insert(ch[x][d],l,mid-1);
if(prio[ch[x][d]]=k) return kth(ch[x][0],k);
return kth(ch[x][1],k-sze[ch[x][0]]-1);
}bool eq(int l1,int l2,int len)
int getlcp(int a,int b) return ans;
}void ins(int x)
int merge(int x,int y)
}void del()
signed main() return 0;
}
字尾平衡樹學習筆記
給定乙個空串s 操作1 代表在 s前加入乙個字母使之成為新s 操作2 代表在詢問在當前 s中有多少連續子串等於給定串t 假設我們已經有了串 s的字尾平衡樹 插入乙個字母c 我們用s i代表原串 s 從第 i個字元開始的字尾 則字尾 cs 與 任意乙個字尾 si 的大小關係可以用 c與s i 的第乙個...
字尾平衡樹
如果需要動態維護字尾陣列,支援在字串前端插入乙個字元,詢問字尾的大小關係,如何做呢?這是乙個不斷插入的問題,可以從增量的角度考慮。我們在前端插入乙個字元,其實就是插入了乙個新的字尾。我們的問題其實就是這個字尾排名多少。我們可以用平衡樹維護一下字尾陣列,從根節點開始二分比較這個字尾的大小,看看它應該被...
學習筆記 字尾系列總結
字尾插到trie樹里。把許多節點壓到一起。節點數量是o n 的 節點可以記錄原串的起始終止位置。可以查詢子串。性質 lca深度為lcp長度 某個點的子樹葉子個數為點所代表的子串的出現次數。按字典序dfs就是字尾排序結果。求法 倍增,基於基數排序 對於sa lcp i,j min hei i 可以列舉...