SPOJ - QTREE Query on a tree 树链剖分+线段树

题目链接


题意:给一棵树,树的边上是有权值的。
输入给n-1条边,有两种操作:

  • CHANGE i j 将第i条边的权值改为j
  • QUERY i j 询问节点i到节点j路径上的权值最大值

思路:

  • 树链剖分处理出每条链,放到数组中,使用线段树来维护。
  • 因为是边上的权值,所以将其转为点上的权值,转变为深度较大的点上的权值。
  • 使用线段树是因为它支持动态查询区间最值和单点修改。

写错了的几次是因为对于使用点上的权值,所以处理同一条链上的最大值的时候,例如 u -> v 的链时,要查询的时u+1 -> v的最大值。

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
#include <string>
#include <math.h>
#include <bitset>
#include <ctype.h>
#define CLR(n,b) memset(n, b, sizeof(n))
using namespace std;
typedef pair<int,int> P;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-9;
const int N = 2e4 + 5;
const int mod = 1e9 + 7;
struct Edge
{
    int u,v,w;
    Edge() {}
    Edge(int a, int b, int c): u(a), v(b), w(c) {}
};
int fa[N],son[N], p[N],fp[N], top[N],dep[N],sz[N];
int a[N];
int pos;
int n,m,k;
vector<Edge> edges;
vector<int> G[N];
void init(int n)
{
    CLR(fa, 0);  CLR(son, -1); CLR(p, -1); CLR(a, 0);
    CLR(fp, -1); CLR(top, 0); CLR(sz, 0); CLR(dep, 0);
    pos = 0; edges.clear();
    for(int i = 0; i <= n; i++) G[i].clear();
}
void addedge(int u, int v, int w)
{
    edges.push_back(Edge(u,v,w));
    edges.push_back(Edge(v,u,w));
    int m = edges.size();
    G[u].push_back(m-2);
    G[v].push_back(m-1);
}


void dfs(int u, int pre, int d)
{
    fa[u] = pre;
    dep[u] = d;
    sz[u] = 1;
    son[u] = -1;
    for(int i = 0; i < G[u].size(); i++)
    {
        Edge &e = edges[G[u][i]];
        int v = e.v;
        if(v == pre) continue;
        dfs(v, u, d+1);
        a[v] = e.w;
        sz[u] += sz[v];
        if(son[u] == -1 || sz[son[u]] < sz[v])
            son[u] = v;
    }
}

void getpos(int u, int sp)
{
    top[u] = sp;
    p[u] = ++pos;
    fp[p[u]] = u;
    if(son[u] == -1) return;
    getpos(son[u], sp);
    for(int i = 0; i < G[u].size(); i++)
    {
        Edge &e = edges[G[u][i]];
        int v = e.v;
        if(v == son[u] || v == fa[u]) continue;
        getpos(v, v);
    }
}


int Max[N<<2];
void build(int rt, int l, int r)
{
    if(l == r)
    {
        Max[rt] = -INF;
        return;
    }
    int mid = l+r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 |1, mid+1, r);
    Max[rt] = max(Max[rt<<1], Max[rt<<1|1]);
}
void update(int pos, int val, int rt, int l, int r)
{
    if(pos < l || pos > r) return;
    int mid = l+r >> 1;
    if(l == r)
    {
        Max[rt] = val;
        return;
    }
    if(pos > mid) update(pos, val, rt << 1 | 1, mid+1, r);
    else update(pos, val, rt << 1, l, mid);
    Max[rt] = max(Max[rt<<1], Max[rt<<1|1]);
}
int query(int L, int R, int rt, int l, int r)
{
    if(L <= l && r <= R) return Max[rt];
    int mid = l+r >> 1;
    int ans = 0;
    if(mid >= L) ans = max(ans, query(L, R, rt<<1, l, mid));
    if(mid < R) ans = max(ans, query(L, R, rt<<1|1, mid+1, r));
    return ans;
}



int Query(int u, int v)
{
    int f1 = top[u], f2 = top[v];
    int ans = 0;
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(f1, f2);
            swap(u, v);
        }

        ans = max(ans, query(p[f1], p[u], 1, 1, n));
        u = fa[f1];
        f1 = top[u];
    }
    if(u == v) return ans;
    if(dep[u] > dep[v]) swap(u, v);
    /**WA**/
    ans = max(ans, query(p[u]+1, p[v], 1, 1, n));
    /****/
    return ans;
}
int t;
int main()
{
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        init(n);
        for(int i = 0; i < n-1; i++)
        {
            int u,v,w;
            scanf("%d%d%d", &u, &v, &w);
            addedge(u,v,w);
        }
        dfs(1,1,0);
        getpos(1,1);
        build(1,1,n);
        for(int i = 1; i <= n; i++)
            update(p[i], a[i], 1, 1, n);
        while(true)
        {
            char cmd[10];
            int x,y;
            scanf("%s", cmd);
            if(cmd[0] == 'D') break;
            scanf("%d%d", &x,&y);
            if(cmd[0] == 'Q')
                printf("%d\n", Query(x,y));
            else
            {
                int u = edges[x*2-2].u, v = edges[x*2-2].v;
                if(dep[u] < dep[v]) swap(u,v);
                update(p[u], y, 1, 1, n);
            }
        }
    }
    return 0;
}
posted @ 2017-09-07 23:04  可达龙  阅读(171)  评论(0编辑  收藏  举报