zoukankan      html  css  js  c++  java
  • poj 2763 Housewife Wind

    Housewife Wind
    Time Limit: 4000MS   Memory Limit: 65536K
    Total Submissions: 12816   Accepted: 3538

    Description

    After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional roads. We say that huts in the same pair directly connected. XX Village is so special that we can reach any other huts starting from an arbitrary hut. If each road cannot be walked along twice, then the route between every pair is unique.

    Since Jiajia earned enough money, Wind became a housewife. Their children loved to go to other kids, then make a simple call to Wind: 'Mummy, take me home!'

    At different times, the time needed to walk along a road may be different. For example, Wind takes 5 minutes on a road normally, but may take 10 minutes if there is a lovely little dog to play with, or take 3 minutes if there is some unknown strange smell surrounding the road.

    Wind loves her children, so she would like to tell her children the exact time she will spend on the roads. Can you help her?

    Input

    The first line contains three integers n, q, s. There are n huts in XX Village, q messages to process, and Wind is currently in hut s. n < 100001 , q < 100001.

    The following n-1 lines each contains three integers a, b and w. That means there is a road directly connecting hut a and b, time required is w. 1<=w<= 10000.

    The following q lines each is one of the following two types:

    Message A: 0 u
    A kid in hut u calls Wind. She should go to hut u from her current position.
    Message B: 1 i w
    The time required for i-th road is changed to w. Note that the time change will not happen when Wind is on her way. The changed can only happen when Wind is staying somewhere, waiting to take the next kid.

    Output

    For each message A, print an integer X, the time required to take the next child.

    Sample Input

    3 3 1
    1 2 1
    2 3 2
    0 2
    1 2 3
    0 3
    

    Sample Output

    1
    3
    
    题意:
    一棵树,节点与节点之间道路是双向的,从节点a走到节点b需要花费c的时间,现在需要你实现以下两个功能:
    1:从当前节点移动到x节点所需要的时间
    2:将编号为x的道路所需花费的时间改为t
    思路:
    对于实现功能1,我们可以借助树状数组,首先按照dfs访问顺序得到经过的点序列(每访问一个节点就记录一下),对于该点序列中某一个点,树状数组维护的值为从根节点走到当前点所在节点所耗费的时间。之后求出lca,即两个点的最近公共祖先,这个可以使用线段树rmq求得。那么从当前节点b移动到x节点所需要的时间
    就是sum(b)+sum(x)-2*sum(lca(b,x))其中sum(a)为从根节点第一次走到节点a所耗费的时间。
    对于2的实现:只要继续在树状数组上操作即可,譬如改变某条路x的权值为t,那么第一次经过这条路时,在树状数组当前位置上改成权值t,第二次经过这条路,在第二次的位置上将权值改为-t。
    AC代码:

    #define _CRT_SECURE_NO_DEPRECATE
    #include <iostream>
    #include <vector>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    #define N_MAX 210000
    #define MAX_N 100000+10
    #define EPS 1e-8
    struct edge {
        int id, to, cost;
        edge(int id = 0, int to = 0, int cost = 0) :id(id), to(to), cost(cost) {}
    };
    int n, q, s;
    int a[N_MAX], b[N_MAX], w[N_MAX];
    vector<edge>G[N_MAX];
    int root;//根可以随意取
    
    int vs[N_MAX * 2];//DFS访问顺序
    int depth[N_MAX * 2];//节点深度
    int id[N_MAX];//各个顶点在vs中首次出现的下标
    int es[N_MAX * 2];//边的下标(i*2+(叶子方向0,根方向1))
    
    int bit[2 * N_MAX];//存储从根节点到顺序访问中第k次访问到的节点的距离和
    int bit_n;
    int sum(int i) {
    
        int s = 0;
        while (i>0) {
            s += bit[i];
            i -= i&-i;
        }
        return s;
    }
    void add(int i, int x) {
        while (i <= bit_n) {
            bit[i] += x;
            i += i&-i;
        }
    }
    
    int index[4 * N_MAX];//维护最小值对应的下标
    int dep[4 * N_MAX];
    void rmq_init(int k, int l, int r, const int *depth) {//第k个节点对应的区间为[l,r)
        if (r - l == 1) {
            index[k] = l;
            dep[k] = depth[l];
        }
        else {
            int chl = 2 * k + 1, chr = 2 * k + 2;//!!!!!
            int mid = (l + r) >> 1;
            rmq_init(chl, l, mid, depth);
            rmq_init(chr, mid, r, depth);
            int min_dep;
            if (dep[chl] < dep[chr]) {
                min_dep = dep[chl];
                index[k] = index[chl];
            }
            else {
                min_dep = dep[chr];
                index[k] = index[chr];
            }
            dep[k] = min_dep;
        }
    }
    
    
    int query(int a, int b, int k, int l, int r) {//查询最小值对应的下标
        if (r <= a || b <= l) {//互不相交
            return INT_MAX;
        }
        if (a <= l&&r <= b) {//[a,b)完全包含k节点对应的区间
            return index[k];
        }
        else {
            int dex_l = query(a, b, k * 2 + 1, l, (l + r) >> 1);
            int dex_r = query(a, b, k * 2 + 2, (l + r) >> 1, r);
            int res;
            if (depth[dex_l] < depth[dex_r]) {
                res = dex_l;
            }
            else res = dex_r;
            if (dex_l == INT_MAX) { res = dex_r; }
            if (dex_r == INT_MAX) { res = dex_l; }
            return res;
        }
    }
    
    void dfs(int v, int p, int d, int&k) {//当前节点v,父亲p,深度d,访问顺序k
        id[v] = k;
        vs[k] = v;
        depth[k++] = d;
        for (int i = 0; i<G[v].size(); i++) {
            edge&e = G[v][i];
            if (e.to != p) {
                add(k, e.cost);
                es[e.id * 2] = k;
                dfs(e.to, v, d + 1, k);
                vs[k] = v;
                depth[k++] = d;
                add(k, -e.cost);
                es[e.id * 2 + 1] = k;
            }
        }
    }
    
    void init(int V) {
        memset(bit, 0, sizeof(bit));
        bit_n = (V - 1) * 2;
        int k = 0;
        dfs(root, -1, 0, k);
        rmq_init(0, 0, 2 * (V - 1) + 1, depth);
    }
    
    int lca(int u, int v) {
        return vs[query(min(id[u], id[v]), max(id[u], id[v]) + 1, 0, 0, 2 * (n - 1) + 1)];//+1是因为线段树区间左闭右开
    }
    
    void solve() {
        memset(depth, 0x3f, sizeof(depth));
        root = n / 2;
        for (int i = 0; i < n - 1; i++) {//n-1条边
            G[a[i] - 1].push_back(edge(i, b[i] - 1, w[i]));
            G[b[i] - 1].push_back(edge(i, a[i] - 1, w[i]));
        }
        init(n);
        int v = s - 1;//当前位置
        int type;
        for (int i = 0; i < q; i++) {
            scanf("%d", &type);
            if (type == 0) {
                int x; scanf("%d", &x);
                int u = x - 1;
                int p = lca(v, u);
                printf("%d
    ", sum(id[v]) + sum(id[u]) - sum(id[p]) * 2);
                v = u;//到达当前位置
            }
            else {
                int x, t;
                scanf("%d%d", &x, &t);
                int k = x - 1;
                add(es[2 * k], t - w[k]);
                add(es[2 * k + 1], w[k] - t);//!!!!
                w[k] = t;
            }
        }
    }
    
    int main() {
        while (scanf("%d%d%d", &n, &q, &s) != EOF) {
            for (int i = 0; i < n - 1; i++) {
                scanf("%d%d%d", a + i, b + i, w + i);
            }
            solve();
            for (int i = 0; i <= n; i++) {
                G[i].clear();
            }
        }
        return 0;
    }
  • 相关阅读:
    ADO.NET朝花夕拾(二)
    使文本框自动适应内容的高度
    jQuery getJSON
    ASP.NET页面生命周期概述
    CSS学习(四)CSS选择符详解
    jQuery dialog 异步调用ashx,webservice数据
    jQuery之小议each()
    jQuery,Ashx发送站内信
    Newtonsoft.Json处理日期问题
    CSS学习(三)带当前标识的横向导航图片美化版
  • 原文地址:https://www.cnblogs.com/ZefengYao/p/7912014.html
Copyright © 2011-2022 走看看