數據結構複習1

數據結構複習1

線段樹、主席樹、平衡樹、樹鏈剖分ios

update【2018.7.23】我放棄指針版的了它欺負我嗚嗚嗚數據結構

線段樹

標記

多個標記考慮優先級ui

知足區間加法就能夠用線段樹

主席樹

細節:spa

  • x和y是節點編號,因此是root[i]不是i
  • 每次複製原來的節點,再新建

平衡樹

Treap

知足平衡樹的性質,同時隨機附加域維護一個小根堆指針

  • rturn,左兒子成爲根 c=t[x].l t[x].l=t[c].r t[c].r=x
  • lturn,右兒子成爲根
  • 插入
    • !x 新建節點
    • 判斷向哪走,遞歸結束時維護堆性質
  • 刪除
    • !x 返回
    • 判斷有幾個,1個的話左右兒子誰繼承他。注意先旋轉再刪本身的技巧
    • 還不到就走
  • rnk, kth, pre, suf
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define lc t[x].l
#define rc t[x].r
const int N = 1e5+5;

inline int read() {
    int x=0, f=1; char c=getchar();
    while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();}
    while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    return x*f;
}

struct meow {
    int x, l, r, v, w, size, rnd;
    meow() {}
    meow(int a) {l=r=0; v=a; w=size=1; rnd=rand();}
} t[N];
int sz, root;

inline void update(int x) {
    t[x].size = t[lc].size + t[rc].size + t[x].w;
}
inline void rturn(int &x) {
    int c = lc; lc = t[c].r; t[c].r = x;
    t[c].size = t[x].size; update(x); x=c;
}
inline void lturn(int &x) {
    int c = rc; rc = t[c].l; t[c].l = x;
    t[c].size = t[x].size; update(x); x=c;
}
void insert(int &x, int v) {
    if(!x) {
        x = ++sz;
        t[x] = meow(v);
    } else {
        t[x].size++;
        if(v == t[x].v) t[x].w++;
        else if(v < t[x].v) {
            insert(lc, v);
            if(t[lc].rnd < t[x].rnd) rturn(x);
        } else {
            insert(rc, v);
            if(t[rc].rnd < t[x].rnd) lturn(x);
        }
    }
}
void erase(int &x, int v) {
    if(!x) return;
    if(v == t[x].v) {
        if(t[x].w > 1) t[x].w--, t[x].size--;
        else if(!lc || !rc) x = lc|rc;
        else if(t[lc].rnd < t[rc].rnd) rturn(x), erase(x, v);
        else lturn(x), erase(x, v);
    } else {
        t[x].size--;
        if(v < t[x].v) erase(lc, v);
        else erase(rc, v);
    }
}
int rnk(int x, int v) {
    if(!x) return 0;
    if(v == t[x].v) return t[lc].size + 1;
    else if(v < t[x].v) return rnk(lc, v);
    else return t[lc].size + t[x].w + rnk(rc, v);
}
int kth(int x, int k) {
    if(!x) return 0;
    if(k <= t[lc].size) return kth(lc, k);
    else if(k <= t[lc].size + t[x].w) return t[x].v;
    else return kth(rc, k - t[lc].size - t[x].w);
}
int ans = 0;
void pre(int x, int v) {
    if(!x) return;
    if(t[x].v < v) ans = x, pre(rc, v);
    else pre(lc, v);
}
void suf(int x, int v) {
    if(!x) return;
    if(t[x].v > v) ans = x, suf(lc, v);
    else suf(rc, v);
}


int n;
int main() {
    freopen("in", "r", stdin);
    srand(2333);
    n = read();
    for(int i=1; i<=n; i++) {
        int c = read(), x = read();
        if(c == 1) insert(root, x);
        else if(c == 2) erase(root, x);
        else if(c == 3) printf("%d\n", rnk(root, x));
        else if(c == 4) printf("%d\n", kth(root, x));
        else if(c == 5) pre(root, x), printf("%d\n", t[ans].v);
        else if(c == 6) suf(root, x), printf("%d\n", t[ans].v);
    }
}

Splay

伸展樹。插入、查詢後將該節點splay到根code

  • rotate 將x轉到父親的位置 注意fa信息的維護
  • splay 將x伸展到父親爲tar的位置 共線時先轉父親
  • 插入
    • !root 新節點是根
    • 已存在v
    • 不存在v,記錄last信息,找到後處理
  • 尋找 將v找到並splay到根
  • 刪除
    • splay到根
    • 多個
    • 沒有兒子,一個兒子
    • 兩個兒子,找左子樹最大節點,splay到左兒子,右兒子接在左兒子右邊
  • rnk, kth, pre, suf
  • 區間操做 [l,r] 將l-1對應的節點splay到左子樹,r+1對應的節點splay到柚子樹,r+1的左兒子子樹就是區間[l,r]
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define lc t[x].ch[0]
#define rc t[x].ch[1]
#define pa t[x].fa
const int N = 1e5+5;

inline int read() {
    int x=0, f=1; char c=getchar();
    while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();}
    while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    return x*f;
}

struct meow {
    int ch[2], fa, v, w, size;
    meow() {}
    meow(int a) {ch[0]=ch[1]=fa=0; v=a; w=size=1;}
} t[N];
int sz, root;
inline void update(int x) {
    t[x].size = t[lc].size + t[rc].size + t[x].w;
}

inline int wh(int x) {return t[pa].ch[1] == x;}
inline void rotate(int x) {
    int f = t[x].fa, g = t[f].fa, c = wh(x);
    if(g) t[g].ch[wh(f)] = x; t[x].fa = g;
    t[f].ch[c] = t[x].ch[c^1]; t[t[f].ch[c]].fa = f;
    t[x].ch[c^1] = f; t[f].fa = x;
    update(f); update(x);
}
inline void splay(int x, int tar) {
    for(; pa != tar; rotate(x))
        if(t[pa].fa != tar) rotate(wh(x) == wh(pa) ? pa : x);
    if(!tar) root = x;
}

void insert(int v) { 
    if(!root) {root = ++sz; t[root] = meow(v); return;}
    int x = root, last = 0;
    while(x) {
        if(v == t[x].v) {
            t[x].w++; t[x].size++; splay(x, 0); return;
        }
        last = x;
        if(v < t[x].v) x = lc;
        else x = rc;
    }
    x = ++sz; t[x] = meow(v);
    if(v < t[last].v) t[last].ch[0] = x;
    else t[last].ch[1] = x;
    t[x].fa = last; 
    splay(x, 0);
}

int find(int v) {
    int x = root;
    while(x) {
        if(v == t[x].v) {splay(x, 0); break;}
        else if(v < t[x].v) x = lc;
        else x = rc;
    }
    return x;
}

void erase(int v) {
    int x = find(v);
    if(t[x].w > 1) t[x].w--, t[x].size--;
    else if(!lc && !rc) root = 0;
    else if(!rc) t[lc].fa = 0, root = lc;
    else if(!lc) t[rc].fa = 0, root = rc;
    else {
        int _ = lc;
        while(t[_].ch[1]) _ = t[_].ch[1];
        splay(_, x);
        t[_].ch[1] = rc; t[rc].fa = _;
        t[_].fa = 0; root = _; 
        update(root);
    }
}

int rnk(int v) {
    int x = root, lsize = 0;
    while(x) {
        if(v == t[x].v) {
            int ans = lsize + t[lc].size + 1;
            splay(x, 0);
            return ans;
        } 
        else if(v < t[x].v) x = lc;
        else lsize += t[lc].size + t[x].w, x = rc;
    }
    return -1;
}
int kth(int k) {
    int x = root;
    while(x) {
        if(k <= t[lc].size) x = lc;
        else if(k <= t[lc].size + t[x].w) return t[x].v;
        else k -= t[lc].size + t[x].w, x = rc;
    }
    return -1;
}
int pre(int v) {
    int x = root, ans = 0;
    while(x) {
        if(t[x].v < v) ans = x, x = rc;
        else x = lc;
    }
    return ans;
}
int suf(int v) {
    int x = root, ans = 0;
    while(x) {
        if(t[x].v > v) ans = x, x = lc;
        else x = rc;
    }
    return ans;
}

int n, ans;
int main() {
    freopen("in", "r", stdin);
    n = read();
    for(int i=1; i<=n; i++) { 
        int c = read(), x = read();
        if(c == 1) insert(x);
        else if(c == 2) erase(x);
        else if(c == 3) printf("%d\n", rnk(x));
        else if(c == 4) printf("%d\n", kth(x));
        else if(c == 5) ans = pre(x), printf("%d\n", t[ans].v);
        else if(c == 6) ans = suf(x), printf("%d\n", t[ans].v);
    }
}

Splay維護序列

再也不看v從左到右從小到大,而是從左到右當作一個序列繼承

提取區間,進行操做遞歸

資瓷區間翻轉等一系列線段樹不能作的操做get

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define lc t[x].ch[0]
#define rc t[x].ch[1]
#define pa t[x].fa

const int N = 1e5+5;

inline int read() {
    int x=0, f=1; char c = getchar();
    while(c < '0' || c > '9') {if(c=='-') f=-1;c=getchar();}
    while(c >= '0' && c <= '9') {x=x*10+c-'0'; c=getchar();}
    return x * f;
}

int n, m;

struct meow {
    int ch[2], fa, w, size, rev;
} t[N];
int sz, root;
inline void update(int x) {
    t[x].size = t[lc].size + t[rc].size + t[x].w;
}
inline int wh(int x) {return t[pa].ch[1] == x;}
inline void paint(int x) {
    t[x].rev ^= 1;
    swap(lc, rc);
}
inline void push_down(int x) {
    if(t[x].rev) {
        paint(lc);
        paint(rc);
        t[x].rev = 0;
    }
}
void rotate(int x) {
    int f = t[x].fa, g = t[f].fa, c = wh(x);
    if(g) t[g].ch[wh(f)] = x; t[x].fa = g;
    t[f].ch[c] = t[x].ch[c^1]; t[t[f].ch[c]].fa = f;
    t[x].ch[c^1] = f; t[f].fa = x;
    update(f); update(x);
}
void splay(int x, int tar) {
    for(; pa != tar; rotate(x))
        if(t[pa].fa != tar) rotate(wh(x) == wh(pa) ? pa : x);
    if(!tar) root = x;
}
void build(int &x, int l, int r) {
    if(l > r) return;
    x = (l+r) >> 1;
    build(lc, l, x-1); build(rc, x+1, r);
    t[lc].fa = t[rc].fa = x;
    t[x].w = 1; 
    update(x);
}
int kth(int k) {
    int x = root;
    while(x) {
        push_down(x);
        if(k <= t[lc].size) x = lc;
        else if(k <= t[lc].size + t[x].w) return x;
        else k -= t[lc].size + t[x].w, x = rc;
    }
    return -1;
}
void print(int x) {
    if(!x) return;
    push_down(x);
    print(lc);
    if(x != 1 && x != n+2) printf("%d ", x-1);
    print(rc);
}

int main() {
    freopen("in", "r", stdin);
    n = read(); m = read(); 
    build(root, 1, n+2);
    for(int i=1; i<=m; i++) {
        int l = read(), r = read(), f, x;
        f = kth(l); splay(f, 0);
        x = kth(r+2); splay(x, root);
        paint(lc);
    }
    print(root);
}

樹鏈剖分

輕重鏈剖分string

dfs1 維護size deep fa heavy

dfs2 維護dfn top

重鏈的dfs序爲一段

子樹的dfs序也爲一段

求一段的時候在重鏈上處理,跳輕邊

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define mid ((l+r) >> 1)
#define lc x<<1
#define rc x<<1|1
#define lson lc, l, mid
#define rson rc, mid+1, r

typedef long long ll;
const int N = 1e5+5;

int n, m, root, P;
inline int read() {
    int x=0, f=1; char c = getchar();
    while(c < '0' || c > '9') {if(c=='-') f=-1;c=getchar();}
    while(c >= '0' && c <= '9') {x=x*10+c-'0'; c=getchar();}
    return x * f;
}

struct edge {int v, ne;} e[N<<1];
int cnt, h[N];
inline void ins(int u, int v) {
    e[++cnt] = (edge) {v, h[u]}; h[u] = cnt;
    e[++cnt] = (edge) {u, h[v]}; h[v] = cnt;
}
int deep[N], size[N], fa[N], hea[N], dfn[N], dfc, top[N], L[N], R[N];
void dfs1(int u) {
    size[u] = 1;
    for(int i=h[u]; i; i=e[i].ne) {
        int v = e[i].v;
        if(v == fa[u]) continue;
        fa[v] = u;
        deep[v] = deep[u]+1;
        dfs1(v);
        size[u] += size[v];
        if(size[v] > size[hea[u]]) hea[u] = v;
    }
}
void dfs2(int u, int anc) {
    dfn[u] = L[u] = ++dfc;
    top[u] = anc;
    if(hea[u]) dfs2(hea[u], anc);
    for(int i=h[u]; i; i=e[i].ne) {
        int v = e[i].v;
        if(v != hea[u] && v != fa[u]) dfs2(v, v);
    }
    R[u] = dfc;
}

int ow[N], w[N];
namespace seg {

struct meow {
    int sum, add;
} t[N<<2];
inline void paint(int x, int l, int r, int v) {
    t[x].sum = (t[x].sum + (ll) v * (r-l+1) %P) %P;
    t[x].add = (t[x].add + v) %P;
}
inline void push_down(int x, int l, int r) {
    if(t[x].add) {
        paint(lson, t[x].add);
        paint(rson, t[x].add);
        t[x].add = 0;
    }
}
inline void merge(int x) {
    t[x].sum = (t[lc].sum + t[rc].sum) %P;
}
void build(int x, int l, int r) {
    if(l == r) t[x].sum = w[l];
    else {
        build(lson);
        build(rson);
        merge(x);
    }
}
void add(int x, int l, int r, int ql, int qr, int v) {
    if(ql <= l && r <= qr) paint(x, l, r, v);
    else {
        push_down(x, l, r);
        if(ql <= mid) add(lson, ql, qr, v);
        if(mid < qr)  add(rson, ql, qr, v);
        merge(x);
    }
}
int que(int x, int l, int r, int ql, int qr) {
    if(ql <= l && r <= qr) return t[x].sum;
    else {
        push_down(x, l, r);
        int ans = 0;
        if(ql <= mid) ans = (ans + que(lson, ql, qr)) %P;
        if(mid < qr)  ans = (ans + que(rson, ql, qr)) %P;
        return ans;
    }
}

}
void add(int x, int y, int v) {
    while(top[x] != top[y]) {
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        seg::add(1, 1, n, dfn[top[x]], dfn[x], v);
        x = fa[top[x]];
    }
    if(dfn[x] > dfn[y]) swap(x, y);
    seg::add(1, 1, n, dfn[x], dfn[y], v);
}
int que(int x, int y) { 
    int ans = 0;
    while(top[x] != top[y]) {
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        ans = (ans + seg::que(1, 1, n, dfn[top[x]], dfn[x])) %P; 
        x = fa[top[x]];
    }
    if(dfn[x] > dfn[y]) swap(x, y);
    ans = (ans + seg::que(1, 1, n, dfn[x], dfn[y])) %P;
    return ans;
}

int main() {
    freopen("in", "r", stdin);
    n = read(); m = read(); root = read(); P = read();
    for(int i=1; i<=n; i++) ow[i] = read();
    for(int i=1; i<n; i++) ins(read(), read());
    dfs1(root); dfs2(root, root);
    for(int i=1; i<=n; i++) w[dfn[i]] = ow[i];
    seg::build(1, 1, n);

    for(int i=1; i<=m; i++) {
        int c = read(), x = read(), y, z;
        if(c == 1) y = read(), z = read(), add(x, y, z);
        else if(c == 2) y = read(), printf("%d\n", que(x, y));
        else if(c == 3) z = read(), seg::add(1, 1, n, L[x], R[x], z);
        else printf("%d\n", seg::que(1, 1, n, L[x], R[x]));
    }
}
相關文章
相關標籤/搜索