SPOJ 6779 Can you answer these queries VII

SPOJ_6779

    这个题目和GSS1的思想是一样的,只不过由于变成了树,所以可以先用树链剖分先将树划分成若干棵线段树再进行求解。

    另外我的代码写得确实比较挫,推荐一份效率比较高的用动态树写的代码:http://ideone.com/wA3Pr

View Code // 轻重边树链剖分
#include<stdio.h>

#include<string.h>

#define MAXD 100010

#define MAXM 200010

#define INF 0x3f3f3f3f

int N, a[MAXD], mc[4 * MAXD], lc[4 * MAXD], rc[4 * MAXD], to[4 * MAXD], sum[4 * MAXD];

int first[MAXD], e, next[MAXM], v[MAXM];

int q[MAXD], fa[MAXD], dep[MAXD], size[MAXD], son[MAXD], top[MAXD], w[MAXD], cnt;

void Swap(int &x, int &y)

{

    int t;

    t = x, x = y, y = t;

}

int Max(int x, int y)

{

    return x > y ? x : y;

}

void add(int x, int y)

{

    v[e] = y;

    next[e] = first[x], first[x] = e ++;

}

void pushdown(int cur, int x, int y)

{

    if(to[cur] != INF)

    {

        int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;

        to[ls] = to[rs] = to[cur];

        sum[ls] = (mid - x + 1) * to[cur], sum[rs] = (y - mid) * to[cur];

        mc[ls] = lc[ls] = rc[ls] = to[cur] > 0 ? sum[ls] : to[cur];

        mc[rs] = lc[rs] = rc[rs] = to[cur] > 0 ? sum[rs] : to[cur];

        to[cur] = INF;

    }

}

void update(int cur, int x, int y)

{

    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;

    sum[cur] = sum[ls] + sum[rs];

    mc[cur] = Max(Max(mc[ls], mc[rs]), rc[ls] + lc[rs]);

    lc[cur] = Max(lc[ls], sum[ls] + lc[rs]);

    rc[cur] = Max(rc[rs], sum[rs] + rc[ls]);

}

void refresh(int cur, int x, int y, int s, int t, int v)

{

    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;

    if(x >= s && y <= t)

    {

        to[cur] = v;

        sum[cur] = v * (y - x + 1);

        mc[cur] = lc[cur] = rc[cur] = v > 0 ? sum[cur] : v;

        return ;

    }

    pushdown(cur, x, y);

    if(mid >= s)

        refresh(ls, x, mid, s, t, v);

    if(mid + 1 <= t)

        refresh(rs, mid + 1, y, s, t, v);

    update(cur, x, y);

}

int Search(int cur, int x, int y, int s, int t, int flag, int &ans, int &ts, int &tc, int tflag)

{

    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;

    if(x >= s && y <= t)

    {

        ans = Max(ans, mc[cur]);

        tc = Max(tc, ts + (tflag == 0 ? lc[cur] : rc[cur]));

        ts += sum[cur];

        return flag == 0 ? lc[cur] : rc[cur];

    }

    pushdown(cur, x, y);

    if(mid >= t)

        return Search(ls, x, mid, s, t, 0, ans, ts, tc, tflag);

    else if(mid + 1 <= s)

        return Search(rs, mid + 1, y, s, t, 1, ans, ts, tc, tflag);

    else

    {

        int ln, rn;

        if(tflag == 0)

            ln = Search(ls, x, mid, s, t, 1, ans, ts, tc, tflag), rn = Search(rs, mid + 1, y, s, t, 0, ans, ts, tc, tflag);

        else

            rn = Search(rs, mid + 1, y, s, t, 0, ans, ts, tc, tflag), ln = Search(ls, x, mid, s, t, 1, ans, ts, tc, tflag);

        ans = Max(ans, ln + rn);

        if(flag == 0)

            return Max(lc[ls], sum[ls] + rn);

        else

            return Max(rc[rs], sum[rs] + ln);

    }

}

void prepare()

{

    int i, j, k, x, rear = 0;

    q[rear ++] = 1;

    dep[1] = 1, fa[1] = 0;

    for(i = 0; i < rear; i ++)

    {

        x = q[i];

        for(j = first[x]; j != -1; j = next[j])

            if(v[j] != fa[x])

            {

                dep[v[j]] = dep[x] + 1;

                fa[v[j]] = x;

                q[rear ++] = v[j];

            }

    }

    size[0] = 0;

    for(i = rear - 1; i >= 0; i --)

    {

        x = q[i];

        son[x] = 0, size[x] = 1;

        for(j = first[x]; j != -1; j = next[j])

            if(v[j] != fa[x])

            {

                size[x] += size[v[j]];

                if(size[v[j]] > size[son[x]])

                    son[x] = v[j];

            }

    }

    memset(top, 0, sizeof(top));

    cnt = 0;

    for(i = 0; i < rear; i ++)

    {

        x = q[i];

        if(!top[x])

        {

            j = x;

            while(j != 0)

                top[j] = x, w[j] = ++ cnt, j = son[j];

        }

    }

}

void init()

{

    int i, j, k, x, y;

    for(i = 1; i <= N; i ++)

        scanf("%d", &a[i]);

    memset(first, -1, sizeof(first));

    e = 0;

    for(i = 1; i < N; i ++)

    {

        scanf("%d%d", &x, &y);

        add(x, y), add(y, x);

    }

    prepare();

    memset(to, 0x3f, sizeof(to));

    for(i = 1; i <= N; i ++)

        refresh(1, 1, N, w[i], w[i], a[i]);

}

void query(int x, int y)

{

    int fx = top[x], fy = top[y], cx, cy, ans, ts, tc;

    cx = cy = ans = 0;

    while(fx != fy)

    {

        if(dep[fx] > dep[fy])

            Swap(fx, fy), Swap(x, y), Swap(cx, cy);

        ts = tc = 0;

        Search(1, 1, N, w[fy], w[y], 0, ans, ts, tc, 1);

        ans = Max(ans, tc + cy);

        ts = tc = 0;

        Search(1, 1, N, w[fy], w[y], 0, ans, ts, tc, 0);

        cy = Max(ts + cy, tc);

        y = fa[fy], fy = top[y];

    }

    if(dep[x] > dep[y])

        Swap(x, y), Swap(cx, cy);

    ts = tc = 0;

    Search(1, 1, N, w[x], w[y], 0, ans, ts, tc, 0);

    ans = Max(ans, tc + cx);

    ts = tc = 0;

    Search(1, 1, N, w[x], w[y], 0, ans, ts, tc, 1);

    ans = Max(ans, tc + cy);

    ans = Max(ans, cx + ts + cy);

    printf("%d\n", ans);

}

void change(int x, int y, int v)

{

    int fx = top[x], fy = top[y];

    while(fx != fy)

    {

        if(dep[fx] > dep[fy])

            Swap(x, y), Swap(fx, fy);

        refresh(1, 1, N, w[fy], w[y], v);

        y = fa[fy], fy = top[y];

    }

    if(dep[x] > dep[y])

        Swap(x, y);

    refresh(1, 1, N, w[x], w[y], v);

}

void solve()

{

    int i, j, a, b, c, op, q;

    scanf("%d", &q);

    for(i = 0; i < q; i ++)

    {

        scanf("%d%d%d", &op, &a, &b);

        if(op == 1)

            query(a, b);

        else

        {

            scanf("%d", &c);

            change(a, b, c);

        }

    }

}

int main()

{

    while(scanf("%d", &N) == 1)

    {

        init();

        solve();

    }

    return 0;

}

 

    就这个题目而言,我写的link-cut-tree的代码要比树链剖分快一些,大概有这么两个原因:①树链剖分或者线段树更新的部分我写得太挫了;②用树链剖分写的话,在求解最大连续和的时候本身就比较麻烦,而link-cut-tree求解的时候则很方便。

View Code // link-cut-tree

你可能感兴趣的:(poj)