[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掉几道恶心标记维护题吧...

posted @ 2012-02-19 15:50  Neroysq  阅读(923)  评论(0编辑  收藏  举报