析合樹……怎麼說呢,應該是一個排列的一種劃分方法,用於處理連續段有關問題。
首先定義連續段:
對於一個排列的一個區間,如果把這個區間的數拿出來排序,是連續的若干個數,即,則稱爲一個連續段。
總感覺直接說劃分方法有點說不清,再說一些定義:
析合樹上的每個點代表的是一個區間,當然它是一棵樹。
每個點的子節點的區間互不相交,且並起來是這個點代表的區間。
點分爲析點和合點兩種:
1.析點:
把這個的子節點重新排列,取任意長度>1的區間,均不是連續段。
2.合點:
……,均是連續段
解釋重新排列:
如果一個值域是[1,10]的點的子節點的值域分別爲[3,6]、[1,2]、[8,10]、[7,7]
那麼重新排列就變成了2,1,4,3
一個重要的結論是:
一個排列一定可以用析合樹劃分出來,即root代表的就是整個排列。
劃分顯然不止一種,但有一種析合樹劃分,即極大的一種(極大不好理解沒有關係),是唯一的,且有很多優美的性質。
當我們拿到一個排列時,你想直接知道root是析點還是合點都很難,所以我們要考慮自下而上,可以用增量法建樹。
假設現在已經搞定了[1…i]的析和森林,我們把每個析合樹的root拿出來放到一個棧裏(代表區間後的在棧頂)
現在,要加入第i+1個位置,先建一個析點就表示這個位置,設爲x。
設要加入的點是x,棧頂的點是y。
那麼一共有三種情況:
- y是一個合點,x能成爲y新的兒子,拿y遞歸加入。
- 1不行時,新生成一個點z,作爲y和x共有合點父親,拿z遞歸加入。
- 1、2都不行時,新生成一個點z,作爲x和棧頂的若干點(儘量少)的共有析點父親,拿z遞歸加入。
當以上三種情況都不行時,說明不能再合併什麼的了,直接把x加入棧頂。
不難得到析合樹的點數是的。
可以知道1、2操作的複雜度就對應樹的點數,但是3操作最壞情況需要遍歷整棵單調棧。
例如:當root是一個兒子個數爲n的析點時,複雜度就變成了
現在需要考慮用奇技淫巧去優化這個。
對一個區間[x…y],求出的i的最小值和最大值,不妨設爲[l…r]
顯然當r>y時,右端點不變,x往左的左段點都不可能是連續段。
那麼對單調棧裏的每個點,維護一個fail指針,它在加入單調棧前,不是要做3操作嗎?失敗了才被加入單調棧,fail記錄的就是倒着合併時第一次r>y的時候。
假設現在有一個新的點要做3操作,先和棧頂判一下,如果不行,就跳到棧頂的fail去,直到跳到同樣的r>y時 或者 是析點了。
很容易證明 可能的析點左分界點 一定在fail鏈上
且這樣做的複雜度是的,因爲一條fail鏈被跳過一次後就一定不會再被跳。
至於[l,r]可以處理個ST表,也可以求相鄰的然後就合併,複雜度一般要一個log,用毛子算法就可以做到
個人覺得這個東西並不是非常好寫,但是利用模塊化思想會清晰很多,大概就是用個struct來表示各種類型,再寫幾個函數來merge、判斷是不是連續段
裸題:
JZOJ6202. c
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
void cmax(int &x, int y) { x < y ? x = y : 0;}
void cmin(int &x, int y) { x > y ? x = y : 0;}
const int N = 2e5 + 5;
int n, a[N], na[N], m, x, y;
int t0[N * 4], t1[N * 4], pl, pr, px0, px1;
#define i0 i + i
#define i1 i + i + 1
void bt(int i, int x, int y) {
if(x == y) { t0[i] = t1[i] = na[x]; return;}
int m = x + y >> 1;
bt(i0, x, m); bt(i1, m + 1, y);
t0[i] = min(t0[i0], t0[i1]);
t1[i] = max(t1[i0], t1[i1]);
}
void ft(int i, int x, int y) {
if(y < pl || x > pr) return;
if(x >= pl && y <= pr) {
cmin(px0, t0[i]);
cmax(px1, t1[i]);
return;
}
int m = x + y >> 1;
ft(i0, x, m); ft(i1, m + 1, y);
}
struct P {
int x, y;
P(){ x = 100000, y = 0;}
P(int _x, int _y) {x = _x, y = _y;}
} c[N];
void bin(P &a, P b) {
cmin(a.x, b.x);
cmax(a.y, b.y);
}
struct nod {
int ty, ls;
P a, b, c, d;
nod() {
a = b = c = d = P();
}
} b[N]; int b0;
nod bin(nod a, nod b) {
bin(a.a, b.a);
bin(a.b, b.b);
a.d = a.c; bin(a.d, b.d);
bin(a.c, b.c);
return a;
}
int len(nod a) { return a.a.y - a.a.x + 1;}
int vlen(nod a) { return a.b.y - a.b.x + 1;}
int pd(nod a) {
return len(a) == vlen(a);
}
int z[N], z0;
int f[18][N];
struct Fail {
int x;
nod a;
} d[N];
int add(int x) {
if(!z0) {
z[++ z0] = x;
return 0;
}
int y = z[z0];
if(!b[y].ty && pd(bin(b[b[y].ls], b[x]))) {
b[y] = bin(b[y], b[x]);
b[y].ls = x;
f[0][x] = y;
z0 --;
return y;
}
if(pd(bin(b[y], b[x]))) {
b[++ b0] = bin(b[y], b[x]);
b[b0].ls = x;
b[b0].ty = 0;
f[0][y] = f[0][x] = b0;
z0 --;
return b0;
}
int t = z0; y = z[t];
nod e = bin(b[y], b[x]);
while(e.d.y <= b[x].a.y && !pd(e)) {
y = z[t];
e = bin(d[t].a, e);
t = d[t].x;
}
if(pd(e)) {
b0 ++;
z[++ z0] = x;
fo(i, t, z0) {
f[0][z[i]] = b0;
b[b0] = bin(b[b0], b[z[i]]);
}
b[b0].ty = 1;
b[b0].ls = x;
z0 = t - 1; return b0;
} else {
z[++ z0] = x;
d[z0].x = t;
d[z0].a = e;
return 0;
}
}
int q[N], r[N], dep[N];
int lca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
fd(i, 17, 0) if(dep[f[i][x]] >= dep[y]) x = f[i][x];
if(x == y) return x;
fd(i, 17, 0) if(f[i][x] != f[i][y]) x = f[i][x], y = f[i][y];
return f[0][x];
}
int xia(int x, int y) {
fd(i, 17, 0) if(dep[f[i][y]] > dep[x]) y = f[i][y];
return y;
}
int ed[N];
int main() {
freopen("c.in", "r", stdin);
freopen("c.out", "w", stdout);
scanf("%d", &n);
fo(i, 1, n) scanf("%d", &a[i]), na[a[i]] = i;
bt(1, 1, n);
fo(i, 1, n - 1) {
pl = a[i], pr = a[i + 1];
if(pl > pr) swap(pl, pr);
px0 = n; px1 = 0;
ft(1, 1, n);
c[i].x = px0; c[i].y = px1;
}
fo(i, 1, n) {
b[++ b0].ty = 1;
b[b0].a = P(i, i);
b[b0].b = P(a[i], a[i]);
b[b0].c = c[i];
b[b0].d = P();
ed[i] = b0;
int x = b0;
do x = add(x); while(x);
}
fo(i, 1, b0) r[f[0][i]] ++;
fo(i, 1, b0) if(!r[i]) q[++ q[0]] = i;
for(int i = 1; i <= q[0]; i ++) {
int x = q[i];
if(f[0][x] && !(-- r[f[0][x]])) q[++ q[0]] = f[0][x];
}
fd(i, q[0], 1) dep[q[i]] = dep[f[0][q[i]]] + 1;
fo(j, 1, 17) fo(i, 1, b0) {
f[j][i] = f[j - 1][f[j - 1][i]];
}
scanf("%d", &m);
fo(i, 1, m) {
scanf("%d %d", &x, &y);
int z = lca(ed[x], ed[y]);
if(b[z].ty) {
pp("%d %d\n", b[z].a.x, b[z].a.y);
} else {
x = xia(z, ed[x]), y = xia(z, ed[y]);
nod w = bin(b[x], b[y]);
pp("%d %d\n", w.a.x, w.a.y);
}
}
}