SPOJ

来源:互联网 发布:请假流程数据库设计 编辑:程序博客网 时间:2024/06/15 05:33

SPOJ - QTREE Query on a tree树链剖分

You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3…N-1.
We will ask you to perfrom some instructions of the following form:
CHANGE i ti : change the cost of the i-th edge to ti
or
QUERY a b : ask for the maximum edge cost on the path from node a to node b
Input
The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.
For each test case:
In the first line there is an integer N (N <= 10000),
In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 1000000),
The next lines contain instructions “CHANGE i ti” or “QUERY a b”,
The end of each test case is signified by the string “DONE”.
There is one blank line between successive tests.
Output
For each “QUERY” operation, write one integer representing its result.
Example
Input:
1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
Output:
1
3

题意:给树的边权,要求维护树上最短路径上的边权最大值

解:
这是一道裸的树链剖分
我们用树链剖分+线段树解这道题


树链剖分程序过程:
数组含义:
fa:父节点编号
top:树链深度最小的结点编号
dep:深度
w:边权转化为点权
tid:树上的点在数据结构中的顺序
son:重儿子
size:以当前结点为根的子树的大小
(1)dfs1:将重儿子找出来
(2)dfs2:将重儿子连成重链
(3)query:通过top与fa数组跳转,将查询中两点向同一条重链上靠,并维护跳转路程中路径的信息。
(4)update:直接修改存树链的数据结构中对应点权即可

注意:边权转点权时,在最后两个查询点跳转到同一条重链时,由于不能算深度较浅的点的点权故最后一次查询应写成RMQ.query(1, n, tid[x]+1, tid[y], 1)


线段树过程
只需注意id >> 1 + 1是不对的,因为加法优先级高于位运算,应写成(id >> 1) + 1。

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <vector>using namespace std;const int MAXN = 10000 + 10;struct Edge{    int t, w, id;    Edge(int a=0, int b=0, int c=0):t(a), w(b), id(c){}};vector<Edge> map[MAXN];int n, edge[MAXN];struct rmq{    int w[MAXN], tree[MAXN << 2];    void init() {        memset(w, 0, sizeof w);        memset(tree, 0, sizeof tree);    }    void build(int l, int r, int id) {        if (l == r) { tree[id] = w[l]; return; }        int mid = l + r >> 1;        build(l, mid, id << 1);        build(mid + 1, r, (id << 1) + 1);        tree[id] = max(tree[id << 1], tree[(id << 1) + 1]);    }    void update(int l, int r, int a, int id, int x) {        if (a == l && r == a) { tree[id] = x; return; }        int mid = l + r >> 1;        if (l <= a && a <= mid) update(l, mid, a, id << 1, x);         if (mid < a && a <= r) update(mid+1, r, a, (id << 1) + 1, x);        tree[id] = max(tree[id << 1], tree[(id << 1) + 1]);    }    int query(int l, int r, int a, int b, int id) {        if (a <= l && r <= b) return tree[id];        int mid = l + r >> 1, res = 0;        if (a <= mid && l <= b) res = max(res, query(l, mid, a, b, id << 1));        if (mid < b && r >= a) res = max(res, query(mid + 1, r, a, b, (id << 1) + 1));        return res;    }}RMQ;struct treeChainSubdivision{    int fa[MAXN], dep[MAXN], tid[MAXN], son[MAXN], top[MAXN], w[MAXN], size[MAXN];    int tot;    void findHeavyEdge(int x, int father, int depth) {        fa[x] = father;        dep[x] = depth;        size[x] = 1;        son[x] = 0;        int maxsize = 0;        for (int i = 0; i < map[x].size(); ++i) {          Edge cur = map[x][i];          if (cur.t == father) continue;          findHeavyEdge(cur.t, x, depth+1);          size[x] += size[cur.t];          w[cur.t] = cur.w;          edge[cur.id] = cur.t;          if (maxsize < size[cur.t]) {            maxsize = size[cur.t];            son[x] = cur.t;          }        }    }    void connectHeavyEdge(int x, int ancestor) {        tid[x] = ++tot;        top[x] = ancestor;        if (son[x] != 0) {          connectHeavyEdge(son[x], ancestor);                 for (int i = 0; i < map[x].size(); ++i)            if (tid[map[x][i].t] == 0)                      connectHeavyEdge(map[x][i].t, map[x][i].t);        }    }     void pointChange(int x, int d) {        RMQ.update(1, n, tid[x], 1, d);    }    int intervalQuery(int x, int y) {        int res = 0;        while (top[x] != top[y]) {          if (dep[top[x]] < dep[top[y]]) swap(x, y);          res = max(res, RMQ.query(1, n, tid[top[x]], tid[x], 1));          x = fa[top[x]];        }        if (dep[x] > dep[y]) swap(x, y);        res = max(res, RMQ.query(1, n, tid[x]+1, tid[y], 1));        return res;    }    void init(){        w[1] = tot = 0;        memset(tid, 0, sizeof tid);        findHeavyEdge(1, 0, 1);        connectHeavyEdge(1, 1);        RMQ.init();        for (int i = 1; i <= n; ++i)          RMQ.w[tid[i]] = w[i];        RMQ.build(1, n, 1);    }}Sub;char s[20];int main(){    freopen("in.txt", "r", stdin);    int T, x, y, a, b, c;    scanf("%d", &T);    while (T--) {      scanf("%d", &n);      for (int i = 1; i <= n; ++i) map[i].clear();      for (int i = 1; i < n; ++i) {        scanf("%d%d%d", &a, &b, &c);        map[a].push_back(Edge(b, c, i));        map[b].push_back(Edge(a, c, i));      }       Sub.init();      while (scanf("%s", s) && s[0] != 'D') {        scanf("%d%d", &x, &y);        if (s[0] == 'Q')          printf("%d\n", Sub.intervalQuery(x, y));        else           Sub.pointChange(edge[x], y);             }    }    return 0;}
原创粉丝点击