動態維護樹的直徑 2019ACM-ICPC上海網絡預選賽 A題 Lightning Routing

2019ACM-ICPC上海網絡預選賽 A題 Lightning Routing I 動態維護樹的直徑

題意及題解

在這裏插入圖片描述

類似題目:CEOI2019 / CodeForces 1192B. Dynamic Diameter

線段樹維護樹的直徑

在這裏插入圖片描述

const int MXN = 4e5 + 7;
const int MXE = 4e5 + 7;
typedef pair<int, LL> piL;
int n, m;
int fid[MXN], lid[MXN], rid[MXN], inde;
int fa[MXN], weight[MXN];
LL dis[MXN];
std::vector<piL > mp[MXN];
struct node {
    int x, y;
    LL z;
}edge[MXE];
void dfs_pre(int u, int ba) {
    fid[u] = ++ inde;
    rid[inde] = u;
    for(auto V: mp[u]) {
        int v = V.fi;
        if(v == ba) continue;
        fa[v] = u;
        weight[v] = V.se;
        dis[v] = dis[u] + V.se;
        dfs_pre(v, u);
        rid[++inde] = u;
    }
    lid[u] = inde;
}
struct lp {
    LL val, lcav, LM, MR, LMR, lazy;
    /*
    len(a, b) = dis[a] + dis[b] - 2 * Min([a <= c <= b] dis[c])
    線段樹維護最大的len(a,b)即爲直徑。但是必須保證[a <= c <= b]
    val = dis[x], lcav = -2 * dis[x]
    LMR爲直徑
    LM = val + lcav
    MR = lcav + val
    LMR = big(LM + val, val + MR)
    */
    int p1, p2, p3, a, b;
    friend lp operator + (const lp&lson, const lp&rson) {
        lp rt;
        rt.p1 = (lson.val >= rson.val ? lson.p1 : rson.p1);
        rt.val = big(lson.val, rson.val);
        rt.lcav = big(lson.lcav, rson.lcav);
        if(lson.LM > rson.LM) rt.LM = lson.LM, rt.p2 = lson.p2;
        else rt.LM = rson.LM, rt.p2 = rson.p2;
        if(lson.MR > rson.MR) rt.MR = lson.MR, rt.p3 = lson.p3;
        else rt.MR = rson.MR, rt.p3 = rson.p3;
        if(lson.LMR > rson.LMR) rt.LMR = lson.LMR, rt.a = lson.a, rt.b = lson.b;
        else rt.LMR = rson.LMR, rt.a = rson.a, rt.b = rson.b;
        if(lson.val + rson.lcav > rt.LM) {
            rt.LM = lson.val + rson.lcav;
            rt.p2 = lson.p1;
        }
        if(lson.lcav + rson.val > rt.MR) {
            rt.MR = lson.lcav + rson.val;
            rt.p3 = rson.p1;
        }
        if(lson.LM + rson.val > rt.LMR) {
            rt.LMR = lson.LM + rson.val;
            rt.a = lson.p2, rt.b = rson.p1;
        }
        if(lson.val + rson.MR > rt.LMR) {
            rt.LMR = lson.val + rson.MR;
            rt.a = lson.p1, rt.b = rson.p3;
        }
        return rt;
    }
}cw[MXN<<2];
#define lson rt << 1
#define rson rt << 1 | 1
void push_up(int rt) { cw[rt] = cw[lson] + cw[rson]; }
void build(int l, int r, int rt) {
    if(l == r) {
        int x = rid[l];
        cw[rt].lazy = 0;
        cw[rt].val = dis[x];
        cw[rt].lcav = - (dis[x] + dis[x]);
        cw[rt].LM = cw[rt].MR = - dis[x];
        cw[rt].LMR = 0;
        cw[rt].p1 = cw[rt].p2 = cw[rt].p3 = cw[rt].a = cw[rt].b = x;
        return ;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1), build(mid + 1, r, rt << 1 | 1);
    push_up(rt);
}
void push_down(int rt) {
    if(cw[rt].lazy == 0) return ;
    cw[lson].val += cw[rt].lazy;
    cw[rson].val += cw[rt].lazy;
    cw[lson].lcav -= cw[rt].lazy + cw[rt].lazy;
    cw[rson].lcav -= cw[rt].lazy + cw[rt].lazy;
    cw[lson].LM -= cw[rt].lazy;
    cw[rson].LM -= cw[rt].lazy;
    cw[lson].MR -= cw[rt].lazy;
    cw[rson].MR -= cw[rt].lazy;
    cw[lson].lazy += cw[rt].lazy;
    cw[rson].lazy += cw[rt].lazy;
    cw[rt].lazy = 0;
}
void update(int L, int R, LL v, int l, int r, int rt) {
    if(L <= l && r <= R) {
        cw[rt].val += v;
        cw[rt].lcav -= v + v;
        cw[rt].LM -= v;
        cw[rt].MR -= v;
        cw[rt].lazy += v;
        return ;
    }
    int mid = (l + r) >> 1;
    push_down(rt);
    if(L > mid) update(L, R, v, mid + 1, r, rson);
    else if(R <= mid) update(L, R, v, l, mid, lson);
    else {
        update(L, mid, v, l, mid, lson), update(mid + 1, R, v, mid + 1, r, rson);
    }
    push_up(rt);
}
LL query(int p, int l, int r, int rt) {
    if(l == r) return cw[rt].val;
    int mid = (l + r) >> 1;
    push_down(rt);
    if(p <= mid) return query(p, l, mid, lson);
    else return query(p, mid + 1, r, rson);
}
#undef lson
#undef rson
namespace LCA {
    int up[MXN][22], lens[MXN];
    int cnt, dfn[MXN], en[MXN], LOG[MXN];
    void dfs(int u, int ba) {
        lens[u] = lens[ba] + 1;
        dfn[++cnt] = u;
        en[u] = cnt;
        for(auto V: mp[u]) {
            int v = V.fi;
            if(v == ba) continue;
            dfs(v, u);
            dfn[++ cnt] = u;
        }
    }
    inline int cmp(int u, int v) { return lens[u] < lens[v] ? u: v; }
    void init() {
        cnt = lens[0] = 0;
        dfs(1, 0);
        LOG[1] = 0;
        for(int i = 2; i <= cnt; ++i) LOG[i] = LOG[i-1] + ((1<<(LOG[i-1]+1))==i);
        for(int i = 1; i <= cnt; ++i) up[i][0] = dfn[i];
        for(int j = 1; (1<<j) <= cnt; ++j)
            for(int i = 1; i + (1<<j) -1 <= cnt; ++i)
                up[i][j] = cmp(up[i][j-1], up[i+(1<<(j-1))][j-1]);
    }
    inline int lca(int x, int y) {
        int l = en[x], r = en[y];
        if(l > r) swap(l, r);
        int k = LOG[r - l + 1];
        return cmp(up[l][k], up[r-(1<<k)+1][k]);
    }
}
LL Get(int a, int b, int c) {
    return query(fid[a], 1, inde, 1) + query(fid[b], 1, inde, 1) - 2 * query(fid[c], 1, inde, 1);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("E://ADpan//in.in", "r", stdin);
    // freopen("E://ADpan//out.out", "w", stdout);
#endif
    n = read();
    for(int i = 1, a, b; i < n; ++i) {
        LL c;
        a = read(), b = read(), c = read();
        mp[a].eb(mk(b, c)), mp[b].eb(mk(a, c));
        edge[i] = {a, b, c};
        assert(c <= 1000000000);
    }
    LCA::init();
    dfs_pre(1, 0);
    build(1, inde, 1);
    m = read();
    char opt[2];
    int x;
    LL y;
    while(m --) {
        scanf("%s", opt);
        x = read();
        if(opt[0] == 'C') {
            y = read();
            assert(y <= 1000000000);
            int px = (fa[edge[x].x] == edge[x].y ? edge[x].x: edge[x].y);
            update(fid[px], lid[px], y - edge[x].z, 1, inde, 1);
            edge[x].z = y;
            weight[px] = y;
        }else {
            int a = cw[1].a, b = cw[1].b;
            int la = LCA::lca(a, x), lb = LCA::lca(b, x);
            printf("%lld\n", big(Get(x, a, la), Get(x, b, lb)));
        }
    }
#ifndef ONLINE_JUDGE
    cout << "time cost:" << 1.0*clock()/CLOCKS_PER_SEC << "ms" << endl;
#endif
    return 0;
}

動態點分治

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章