[SPOJ] QTREE1-2 [BZOJ] 1036 动态树——part.1
WC回来后无论如何都忍不住搞动态树的冲动了,因为冬令营上各路神牛都讲动态树啊。
看了一下往年的论文,大概知道了动态树是什么东西——在树上利用平衡树来给暴力加速。
代码还是比较好写的,没什么标记也就100行左右(当然这是水题级别的),于是刷了几道水题。
1.QTREE
树上修改单边,询问路径上最大的边权。
找到lca后直接在两截splay上取个max。
#include <stdio.h> #include <string.h> const int nmax = 10000, mmax = nmax * 2, oo = ~0U >> 1; int n, tot = 1, t; int fst[nmax + 18], pnt[mmax + 18], cst[mmax + 18], nxt[mmax + 18]; char com[10]; int k, l, r, ans, q[nmax + 18], qh, qt; bool ed[nmax + 18]; void add(int s, int t, int c){pnt[++tot] = t, nxt[tot] = fst[s], cst[tot] = c, fst[s] = tot;} void update(int &a, int b){if (a < b) a = b;} int max(int a, int b){return a > b ? a : b;} struct Splaynode { Splaynode *chi[2], *p; int k, m; inline void sc(Splaynode *k, int d){chi[d] = k, k->p = this;} inline bool dir(){return this == p->chi[1];} inline void update(){m = max(k, max(chi[0]->m, chi[1]->m));} }*pe[nmax + 18], *ep[nmax + 18], *null; inline void rotate(Splaynode *t) { Splaynode *p = t->p; bool d = !t->dir(); if (p->p != null && (p->p->chi[0] == p || p->p->chi[1] == p)) p->p->sc(t, p->dir());else t->p = p->p; p->sc(t->chi[d], !d); t->sc(p, d); p->update(); } inline void splay(Splaynode *t) { while (t->p != null && (t->p->chi[0] == t || t->p->chi[1] == t)) if (t->p->p == null || (t->p->p->chi[0] != t->p && t->p->p->chi[1] != t->p)) rotate(t); else t->dir() == t->p->dir() ? (rotate(t->p), rotate(t)) : (rotate(t), rotate(t)); t->update(); } inline Splaynode *access(Splaynode *a) { Splaynode *b; for (b = null; a != null; a = a->p) splay(a), a->chi[1] = b, (b = a)->update(); return b; } inline void bfs() { memset(ed, 0, sizeof(ed)); pe[1]->chi[0] = pe[1]->chi[1] = pe[1]->p = null, pe[1]->k = pe[1]->m = -oo; ed[1] = q[qh = qt = 1] = 1; for (int i; qh <= qt; ++qh) for (i = fst[q[qh]]; i; i = nxt[i]) if (!ed[pnt[i]]) { ed[pnt[i]] = 1; pe[pnt[i]]->chi[0] = pe[pnt[i]]->chi[1] = null; pe[pnt[i]]->k = pe[pnt[i]]->m = cst[i];pe[pnt[i]]->p = pe[q[qh]]; ep[i >> 1] = pe[pnt[i]], q[++qt] = pnt[i]; } } int main() { freopen("qtree.in", "r", stdin); freopen("qtree.out", "w", stdout); null = new Splaynode; null->m = null->k = -oo; for (int i = 1; i <= nmax; ++i) pe[i] = new Splaynode; scanf("%d", &t); while (t--) { memset(fst, 0, sizeof(fst)); scanf("%d", &n);tot = 1; for (int i = 1, ss, tt, cc; i < n; ++i) scanf("%d%d%d", &ss, &tt, &cc), add(ss, tt, cc), add(tt, ss, cc); for (bfs(); ;) { scanf("%s", com); if (com[0] == 'D') break; if (com[0] == 'C') { scanf("%d%d", &k, &l); splay(ep[k]); ep[k]->k = l; ep[k]->update(); } else { scanf("%d%d", &l, &r); Splaynode *a = pe[l], *b = pe[r], *c; if (a == b) {printf("0\n");continue;} access(a); c = access(b); ans = 1 << 31; update(ans, c->chi[1]->m); if (a != c) splay(a), update(ans, a->m); printf("%d\n", ans); } } } return 0; }
2.QTREE2
树上询问一条路径的长度或者上面第k个节点。
求lca统计长度或者判一下找节点...
#include <stdio.h> #include <string.h> const int nmax = 10000, mmax = nmax * 2; int t, n, tot, l, r, k, q[nmax + 18], qh, qt, d[nmax + 18]; int fst[nmax + 18], nxt[mmax + 18], pnt[mmax + 18], cst[mmax + 18]; char str[10]; bool ed[nmax + 18]; inline void add(int s, int t, int c){pnt[++tot] = t, nxt[tot] = fst[s], fst[s] = tot, cst[tot] = c;} struct Spode { int k, s, sze, who; Spode *chi[2], *p; inline bool dir(){return this == p->chi[1];} inline bool pcs(){return p->chi[1] == this || p->chi[0] == this;} inline void update(){s = chi[0]->s + chi[1]->s + k, sze = chi[0]->sze + chi[1]->sze + 1;} }pe[nmax + 18], *null; inline void rotate(Spode *a) { Spode *b = a->p; bool d = !a->dir(); if (b->pcs()) b->p->chi[b->dir()] = a; a->p = b->p, b->p = a, b->chi[!d] = a->chi[d], a->chi[d]->p = b, a->chi[d] = b; b->update(); } inline void splay(Spode *a) { while (a->p != null && a->pcs()) if (a->p->p == null || !a->p->pcs()) rotate(a); else a->dir() == a->p->dir() ? (rotate(a->p), rotate(a)) : (rotate(a), rotate(a)); a->update(); } inline Spode *access(Spode *a) { Spode *b; for (b = null; a != null; a = a->p) splay(a), a->chi[1] = b, (b = a)->update(); return b; } inline void bfs() { memset(ed, 0, sizeof(ed)); ed[q[qh = qt = 1] = 1] = 1;pe[1].p = null; for (int i, p; qh <= qt; ++qh) for (pe[q[qh]].sze = 1, pe[q[qh]].chi[0] = pe[q[qh]].chi[1] = null, i = fst[q[qh]]; i; i = nxt[i]) if (!ed[p = pnt[i]]) d[p] = d[q[qh]] + 1, ed[p] = 1, q[++qt] = p, pe[p].k = pe[p].s = cst[i], pe[p].p = &pe[q[qh]]; } int find(Spode *a, int k) { for (;;) if (a->chi[0]->sze + 1 == k) return a->who; else if (a->chi[0]->sze < k) k-=a->chi[0]->sze + 1, a = a->chi[1]; else a = a->chi[0]; } int main() { freopen("QTREE2.in", "r", stdin); freopen("QTREE2.out", "w", stdout); null = new Spode; null->s = null->k = null->sze = 0; for (int i = 1; i <= nmax; ++i) pe[i].who = i, pe[i].sze = 1; for (scanf("%d", &t); t--;) { scanf("%d", &n);tot = 1; memset(fst, 0, sizeof(fst)); for (int i = 1, ss, tt, cc; i < n; ++i) scanf("%d%d%d", &ss, &tt, &cc), add(ss, tt, cc), add(tt, ss, cc); bfs(); for (Spode *a, *b, *c; scanf("%s", str), str[1] != 'O';) if (str[1] == 'I') { scanf("%d%d", &l, &r); d[l] > d[r] ? (a = &pe[l], b = &pe[r]) : (a = &pe[r], b = &pe[l]); access(a); c = access(b); splay(a); printf("%d\n", l == r ? 0 : a->s + c->chi[1]->s); } else { scanf("%d%d%d", &l, &r, &k); a = &pe[l], b = &pe[r]; access(a), c = access(b); splay(a); if (a == c) splay(c), printf("%d\n", find(c, c->chi[0]->sze + k)); else if (a->sze >= k) printf("%d\n", find(a, a->sze - k + 1)); else splay(c), printf("%d\n", find(c, k - a->sze + c->chi[0]->sze)); } } return 0; }
3.bzoj 1036
差不多就是上面两道合起来,不过没有了找第k个点。
维护两个标记就行了。
#include <stdio.h> #include <string.h> const int nmax = 30000, mmax = nmax * 2, oo = 30000 + 1; int fst[nmax + 18], pnt[mmax + 18], nxt[mmax + 18], tot; int n, m, q[nmax + 18], qt, qh, u, v, ans; bool ed[nmax + 18]; char str[10]; inline void add(int s, int t){nxt[++tot] = fst[s];pnt[tot] = t;fst[s] = tot;} inline int max(int a, int b){return a > b ? a : b;} struct Spode { int k, s, m; Spode *chi[2], *p; inline bool dir(){return this == p->chi[1];} inline bool pcs(){return this == p->chi[1] || this == p->chi[0];} inline void update(){m = max(k, max(chi[0]->m, chi[1]->m)), s = k + chi[0]->s + chi[1]->s;} }pe[nmax + 18], *null, *a, *b, *c; inline void rotate(Spode *a) { Spode *b = a->p; bool d = a->dir(); a->p = b->p; if (b->pcs()) b->p->chi[b->dir()] = a; if (a->chi[!d] != null) a->chi[!d]->p = b; b->p = a, b->chi[d] = a->chi[!d], a->chi[!d] = b; b->update(); } inline void splay(Spode *a) { while (a->p != null && a->pcs()) if (a->p->p == null || !a->p->pcs()) rotate(a); else a->dir() == a->p->dir() ? (rotate(a->p), rotate(a)) : (rotate(a), rotate(a)); a->update(); } inline Spode *access(Spode *a) { Spode *b = null; for (; a != null; a = a->p) splay(a), a->chi[1] = b, (b = a)->update(); return b; } void bfs() { pe[ed[q[qh = qt = 1] = 1] = 1].p = null; for (int i; qh <= qt; ++qh) for (pe[q[qh]].chi[0] = pe[q[qh]].chi[1] = null, i = fst[q[qh]]; i; i = nxt[i]) if (!ed[pnt[i]]) ed[pnt[i]] = 1, pe[pnt[i]].p = &pe[q[qh]], q[++qt] = pnt[i]; } int main() { freopen("1036.in", "r", stdin); freopen("1036.out", "w", stdout); null = new Spode; null->k = null->m = -oo, null->s = 0; scanf("%d", &n); for (int i = 1, ss, tt; i < n; ++i) scanf("%d%d", &ss, &tt), add(ss, tt), add(tt, ss); for (int i = 1; i <= n; ++i) scanf("%d", &pe[i].k), pe[i].m = pe[i].s = pe[i].k; for (bfs(), scanf("%d", &m); m--;) if (scanf("%s%d%d", str, &u, &v), str[1] == 'H') splay(a = &pe[u]), pe[u].k = v, pe[u].update(); else { access(a = &pe[u]); c = access(b = &pe[v]); splay(a); printf("%d\n", str[1] == 'M' ? max(c->k, max(c->chi[1]->m, a == c ? -oo : a->m)) : (c->k + c->chi[1]->s + (a == c ? 0 : a->s))); } return 0; }
呃...这几道实在是太水了,我自己都看不下去了,先去多练几下树链剖分/块状树,再来A掉几道恶心标记维护题吧...