poj 2763 Housewife Wind

来源:互联网 发布:hd网络是什么意思啊 编辑:程序博客网 时间:2024/05/19 02:39

Problem

poj.org/problem?id=2763
vjudge.net/contest/28982#problem/B

Reference

poj2763(树链剖分 - 边权)

Meaning

一棵 n 个点的树,每条边都有一个边权。一个人开始在 s 结点。两种操作:

  • 0 u:询问人从 s 走到 u 要走多久,之后人就走到了 u 这个点(即 s 更新为 u)
  • 1 i w:把第 i 条边的权值改成 w

Analysis

考虑树链剖分。权值是在边上,要把权值“转移”到点上
策略是:对于每一条边 e 的两个端点 f 和 t,如果 depth[f] > depth[t],就把边权记到 f 上,否则记到 t 上(即把边权转移到深度更大的端点处)。

Code

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N = 100000;int head[N+1], from[N<<1], to[N<<1], nxt[N<<1], w[N<<1];void add_edge(int f, int t, int c, int sz){    from[sz] = f;    to[sz] = t;    w[sz] = c;    nxt[sz] = head[f];    head[f] = sz;}int dep[N+1], fa[N+1], son[N+1], tsz[N+1];int tid[N+1], pos[N+1], top[N+1], tm;void heavy_light(int v, int f, int d){    dep[v] = d;    fa[v] = f;    tsz[v] = 1;    son[v] = -1;    for(int i = head[v]; ~i; i = nxt[i])        if(to[i] != f)    {        heavy_light(to[i], v, d + 1);        tsz[v] += tsz[to[i]];        if(son[v] == -1 || tsz[to[i]] > tsz[son[v]])            son[v] = to[i];    }}void decompose(int v, int t){    top[v] = t;    pos[v] = ++tm;    tid[pos[v]] = v;    if(son[v] == -1)        return;    decompose(son[v], t);    for(int i = head[v]; ~i; i = nxt[i])        if(to[i] != fa[v] && to[i] != son[v])            decompose(to[i], to[i]);}int tree[N+1<<2];inline void pushup(int x){    tree[x] = tree[x<<1] + tree[x<<1|1];}void update(int p, int v, int l, int r, int rt){    if(l == r)    {        tree[rt] = v;        return;    }    int m = l + r >> 1;    if(p > m)        update(p, v, m+1, r, rt<<1|1);    else        update(p, v, l, m, rt<<1);    pushup(rt);}int sum(int ql, int qr, int l, int r, int rt){    if(ql <= l && r <= qr)        return tree[rt];    if(qr < l || r < ql)        return 0;    int m = l + r >> 1;    return sum(ql, qr, l, m, rt<<1) +        sum(ql, qr, m+1, r, rt<<1|1);}int query(int l, int r, int n){    int ans = 0;    while(top[l] != top[r])    {        if(dep[top[l]] < dep[top[r]])            swap(l, r);        ans += sum(pos[top[l]], pos[l], 1, n, 1);        l = fa[top[l]];    }    if(l != r) // 必须要这个判断    {        if(dep[l] > dep[r])            swap(l, r);        // 当处于同一条链        // 上面的那端要往下退一个点 -> son[l]        // 因为 l 点记得权值是它上面那条边的        // 而那条边不在查询路径上        ans += sum(pos[son[l]], pos[r], 1, n, 1);    }    return ans;}int a[N+1] = {0}; // 结点 i 的初始权值int mp[N]; // 第 i 条边的权值记载 mp[i] 结点上void build(int l, int r, int rt){    if(l == r)    {        tree[rt] = a[tid[l]];        return;    }    int m = l + r >> 1;    build(l, m, rt<<1);    build(m+1, r, rt<<1|1);    pushup(rt);}int main(){    int n, q, s;    scanf("%d%d%d", &n, &q, &s);    memset(head, ~0, sizeof head);    for(int i = 1, f, t, c, sz = 0; i < n; ++i)    {        scanf("%d%d%d", &f, &t, &c);        add_edge(f, t, c, sz++);        add_edge(t, f, c, sz++);    }    heavy_light(1, 0, 1);    tm = 0;    decompose(1, 1);    // 对每一条边,都映射到它深度更大的那个端点    // 并把它的权值记载那个映射点上    for(int i = 1, j = 0; i < n; ++i, j += 2)        if(dep[from[j]] > dep[to[j]])            a[mp[i] = from[j]] = w[j];        else            a[mp[i] = to[j]] = w[j];    build(1, n, 1);    for(int op, v, e; q--; )    {        scanf("%d", &op);        if(op == 0)        {            scanf("%d", &v);            printf("%d\n", query(s, v, n));            s = v;        }        else        {            scanf("%d%d", &e, &v);            // 更新边就变成更新点            // mp[e] 找到要更新的点            update(pos[mp[e]], v, 1, n, 1);        }    }    return 0;}
原创粉丝点击