無旋Treap
1 匹配(match.c/cpp/pas)
1.1 題目描述
給定一個僅含小寫字母的字串 S[0..n-1],對於一個詢問 (p, q, len),我們想知道它的
兩個子串 S[p..p+len-1]、S[q..q+len-1] 是否相同。更多地,我們希望在對串 S 完成一些操
作之後還能高效地得到這個結果。 我們具體要維護以下幾個操作(其中 L 為操作之前的串
長):
● 1 p c:在下標 p 之前插入一個小寫字母 c,0<=p<=L,p=0 意味在頭插入,p=L
意味在尾插入;
● 2 p: 刪除 S[p],其中 0<=p<L;
● 3 p q: 將 S[p..q] 翻轉為 S[q..p],例如 batta 經過 “3 1 3” 之後為 bttaa;
● 4 p q len: 表示一次詢問操作,詢問 S[p..p+len-1] 與 S[q..q+len-1] 是否相同,其
中 0<=p<=p+len-1<L,0<=q<=q+len-1<L。
1.2 輸入格式
第 1 行為兩個整數 n, m,分別表示字串的初始長度和操作次數;
第 2 行為一個長度為 n 的字串;
接下來 m 行,每行為一個操作。
1.3 輸出格式
僅一行一個整數,表示詢問相同的次數。
1.4 樣例輸入
4 4
aacb
2 2 // aab
1 2 b // aabb
3 1 2 // abab
4 0 2 2 // ab == ab
1.5 樣例輸出
1
1.6 資料範圍與約定
對於前 20%的資料滿足 n,m≤1000;
對於前 70%的資料滿足僅含有 3、4 兩種操作;
對於 100%的資料滿足 1≤n, m≤200000。
平衡樹維護序列的裸題,考慮在每個結點維護以該結點為根的子樹的中序字串的雜湊值(記為 hash[u][0]),以及該字串翻轉後的雜湊值(記為 hash[u][1]),則有:hash[u][0] =hash[child[u][0]][0] * pow[size[child[u][1]] + 1] + character[u] * pow[size[child[u][1]]] +hash[child[u][1]][0],其中 child[u][0/1] 表示 u 的左/右兒子,size[u] 表示以 u 為根的子樹大小,pow[i] 表示雜湊的進位制 BASE 的 i 次方。hash[u][1] 的計算同理,有:hash[u][1] =hash[child[u][0]][1] + character[u] * pow[size[child[u][0]]] + hash[child[u][1]][1] *pow[size[child[u][0]] + 1]。
注意在給一個結點打上翻轉標記時,不僅要交換其左右兒子,還要交換 hash[u][0] 和hash[u][1] 的值。比較時通過區間提取,獲得兩個區間對應字串的雜湊值,然後直接判斷是否相等即可。這道題可直接自然溢位。
#include<bits/stdc++.h> #define int long long using namespace std; mt19937 rnd(time(0)); int in() { int x = 0, f = 1; char ch; for(ch = getchar(); (ch < '0' || ch > '9') && ch != '-'; ch = getchar()); if(ch == '-')ch = getchar(); do x = x * 10 + ch - '0', ch = getchar(); while(ch >= '0' && ch <= '9'); return x * f; } int root, tot = 0; unsigned int pw1[800005], pw2[800005], bas2 = 233, bas1 = 421; struct node { char ch; int rd, tag; int ls, rs, siz; unsigned int h1, h2; unsigned int hh1, hh2; } q[800005]; int New(char ch) { q[++tot].ch = ch; q[tot].rd = rnd(); q[tot].siz = 1; q[tot].h1 = q[tot].h2 = ch; q[tot].hh1 = q[tot].hh2 = ch; return tot; } void push(int o) { if(q[o].tag) { swap(q[o].h1, q[o].h2); // swap(q[o].hh1,q[o].hh2); swap(q[o].ls, q[o].rs); if(q[o].ls)q[q[o].ls].tag ^= 1; if(q[o].rs/**/)q[q[o].rs].tag ^= 1; q[o].tag = 0; } } void up(int o) { q[o].siz = q[q[o].ls].siz + q[q[o].rs].siz + 1; push(q[o].ls),push(q[o].rs); q[o].h1 = (q[q[o].ls].h1 + q[o].ch * pw1[q[q[o].ls].siz] + q[q[o].rs].h1 * pw1[q[q[o].ls].siz + 1]); q[o].h2 = (q[q[o].rs].h2 + q[o].ch * pw1[q[q[o].rs].siz] + q[q[o].ls].h2 * pw1[q[q[o].rs].siz + 1]); // q[o].hh1=(q[q[o].ls].hh1+q[o].ch*pw2[q[q[o].ls].siz]+q[q[o].rs].hh1*pw2[q[q[o].ls].siz+1]); // q[o].hh2=(q[q[o].rs].hh2+q[o].ch*pw2[q[q[o].rs].siz]+q[q[o].ls].hh2*pw2[q[q[o].rs].siz+1]); } void split(int o, int s, int &l, int &r) { if(!o) { l = r = 0; return; } push(o);// if(q[q[o].ls].siz + 1 <= s) { l = o; split(q[o].rs, s - q[q[o].ls].siz - 1, q[l].rs, r); } else { r = o; split(q[o].ls, s, l, q[r].ls); } up(o);// } int merge(int l, int r) { if(!l || !r)return l | r; // int o; if(q[l].rd <= q[r].rd) { push(l); o = l; q[o].rs = merge(q[l].rs, r); } else { push(r); o = r; q[o].ls = merge(l, q[r].ls); } up(o);// return o; } void write(int o) { if(!o)return; push(o); write(q[o].ls); putchar(q[o].ch); write(q[o].rs); } char s[800005]; signed main() { freopen("match.in", "r", stdin); freopen("match.out", "w", stdout); int n = in(), m = in(); pw1[0] = pw2[0] = 1; for(int i = 1; i <= m + n; i++)pw1[i] = pw1[i - 1] * bas1; for(int i = 1; i <= m + n; i++)pw2[i] = pw2[i - 1] * bas2; scanf("%s", s + 1); for(int i = 1; i <= n; i++) { int o = New(s[i]); root =/**/merge(root, o); } int ans = 0; for(int i = 1; i <= m; i++) { int op = in(); if(op == 1) { int p = in(); char o = getchar(); int x, y, z; split(root, p, x, y); z = New(o); root = merge(merge(x, z), y); } if(op == 2) { int p = in(); int x, y, z; split(root, p, x, y); split(y, 1, y, z); root = merge(x, z); } if(op == 3) { int l = in(), r = in(); int x, y, z; split(root, l, x, y); split(y, r - l + 1, y, z); q[y].tag ^= 1; root = merge(merge(x, y), z); } if(op == 4) { int l = in(), r = in(), len = in(), x, y, z; unsigned int h1, hh1, h2, hh2; split(root, l, x, y); split(y, len, y, z); h1 = q[y].h1; /*hh1=q[y].hh1;*/ root = merge(merge(x, y), z); split(root, r, x, y); split(y, len, y, z); h2 = q[y].h1; /*hh2=q[y].hh1;*/ root = merge(merge(x, y), z); if(h1 == h2/*&&hh1==hh2*/)ans++; } // write(root); // puts(""); } printf("%lld", ans); return 0; } /* 4 4 aacb 2 2 1 2 b 3 1 2 4 0 2 2 */