HYSBZ

来源:互联网 发布:dell笔记本 centos 编辑:程序博客网 时间:2024/06/03 08:54

树链剖分就是将一个树的路径转化成重链和轻链,对其节点或者边就行编号,从而可以转化成其他的数据结构问题来解决问题。树链剖分有些类似莫队,也就是相当于把树的路径进行了分块。

数组的含义:

fa[]每个节点的父节点
num[]每个节点子节点的个数(包含自己)
son[v]与v在同一重链的重儿子
top[v]节点v所在链的顶端节点(v可以是一个单独的点,相当于自己组成一条重链)
pos[v]节点v编号后在线段树中的编号
pre[v]v节点之前的编号
deep[v]节点v在树中的深度(根深度为1)

修改或者查询时:

对于[u,v]区间,f1=top[u],f2=top[v],ql,qr分别为左右端点
有两种情况(deep[f1]>deep[f2]):
f1!=f2: ql=pos[top[u]],qr=pos[u],再更新u=fa[top[u]]
f1==f2: ql=pos[u],qr=pos[v] (deep[u] < deep[v])
重复循环上面的过程,ql,qr就是需要查询和修改的左右区间

【HYSBZ - 1036 树的统计】

这个题是裸的树剖加线段树
  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

  输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

  对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

41 22 34 14 2 1 312QMAX 3 4QMAX 3 3QMAX 3 2QMAX 2 3QSUM 3 4QSUM 2 1CHANGE 1 5QMAX 3 4CHANGE 3 6QMAX 3 4QMAX 2 4QSUM 3 4

Sample Output

412210656516
#include<cstdio>#include<algorithm>#include<vector>#include<cstring>using namespace std;const int maxn = 1e5 + 5;struct node {    int l, r, maxx, sum;}tree[maxn<<2];int pos[maxn], pre[maxn], value[maxn], son[maxn], num[maxn], top[maxn], deep[maxn],fa[maxn];int n, tot, q;vector<int>e[maxn];void dfs1(int u,int f,int dep){    deep[u] = dep;    num[u] = 1;    fa[u] = f;    for (int i = 0; i < e[u].size(); i++) {        int v = e[u][i];        if (v == fa[u]) continue;        dfs1(v, u, dep + 1);        num[u] += num[v];        if (num[v] > num[son[u]])            son[u] = v;    }}void dfs2(int u,int tp){    pos[u] = ++tot; pre[pos[u]] = u;    top[u] = tp;    if (son[u]) dfs2(son[u], tp);    for (int i = 0; i < e[u].size(); i++) {        int v = e[u][i];        if (v == fa[u] || v == son[u]) continue;        dfs2(v, v);    }}inline void pushup(int rt){    tree[rt].maxx = max(tree[rt << 1].maxx, tree[rt << 1 | 1].maxx);    tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;}void build(int l, int r, int rt){    tree[rt].l = l; tree[rt].r = r;    if (l == r) {        tree[rt].maxx = tree[rt].sum = value[pre[l]];        return;    }    int mid = l + r >> 1;    build(l, mid, rt << 1);    build(mid + 1, r, rt << 1 | 1);    pushup(rt);}void update(int pos, int rt, int val){    if (tree[rt].l == tree[rt].r) {        tree[rt].sum = tree[rt].maxx = val;        return;    }    int mid = tree[rt].l + tree[rt].r >> 1;    if (pos <= mid) update(pos, rt << 1, val);    else if (pos > mid) update(pos, rt << 1 | 1, val);    pushup(rt);}pair<int, int> query(int l, int r, int rt){    pair<int, int>ret;    if (l == tree[rt].l&&r == tree[rt].r) {        ret.first = tree[rt].maxx;        ret.second = tree[rt].sum;        return ret;    }    int mid = tree[rt].l + tree[rt].r >> 1;    if (r <= mid) return query(l, r, rt << 1);    else if (l > mid) return query(l, r, rt << 1 | 1);    else {        pair<int, int>a, b;        a = query(l, mid, rt << 1);        b = query(mid + 1, r, rt << 1 | 1);        ret.first = max(a.first, b.first);        ret.second = a.second + b.second;        return ret;    }    pushup(rt);}int getsum(int u, int v){    int f1 = top[u], f2 = top[v], ret = 0;    while (f1 != f2) {        if (deep[f1] < deep[f2]) {            swap(f1, f2); swap(u, v);        }        ret += query(pos[top[u]], pos[u], 1).second;        u = fa[f1]; f1 = top[u];    }    if (deep[u] < deep[v]) swap(u, v);    ret += query(pos[v], pos[u], 1).second;    return ret;}int getmax(int u, int v){    int f1 = top[u], f2 = top[v], ret = -0x3f3f3f3f;    while (f1 != f2) {        if (deep[f1] < deep[f2]) {            swap(f1, f2); swap(u, v);        }        ret =max(ret, query(pos[top[u]], pos[u], 1).first);        u = fa[f1]; f1 = top[u];    }    if (deep[u] < deep[v]) swap(u, v);    ret = max(ret, query(pos[v], pos[u], 1).first);    return ret;}int main(){    scanf("%d",&n);    for (int i = 1; i < n; i++) {        int a, b;        scanf("%d%d",&a,&b);        e[a].push_back(b);        e[b].push_back(a);    }    for (int i = 1; i <= n; i++) scanf("%d",&value[i]);    dfs1(1, 1, 1);    dfs2(1, 1);    build(1, tot, 1);    scanf("%d",&q);    for (int i=1 ; i <= q; i++) {        char op[10];        int u, v;        scanf("%s%d%d",op,&u,&v);        if (strcmp(op, "QSUM") == 0) {            printf("%d\n",getsum(u,v));        }        else if (strcmp(op, "QMAX") == 0) {            printf("%d\n", getmax(u, v));        }        else {            update(pos[u], 1, v);        }    }    return 0;}
原创粉丝点击