Luogu 4949 最短距离

这就是个水题。

一开始想把整个环找出来断开当一条链,然后其他部分正常链剖,两个点之间的路径如果经过环就考虑一下走哪边更快。

但是这样子还是太麻烦了。

我们可以直接断开环上的一条边,然后正常链剖,只要在查询的时候强制走这条边然后取个$min$就好了。

时间复杂度$O(nlog^2n)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

const int N = 1e5 + 25;

int n, qn, tot = 0, head[N], ufs[N], sx, sy, sid, pid[N];
int dfsc = 0, id[N], siz[N], son[N], fa[N], top[N], dep[N];
ll sv, eVal[N], w[N];

struct Edge {
    int to, nxt, eid;
    ll val;
} e[N << 1];

inline void add(int from, int to, int eid, ll val) {
    e[++tot].to = to;
    e[tot].eid = eid;
    e[tot].val = val;
    e[tot].nxt = head[from];
    head[from] = tot;
}

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

template <typename T>
inline void chkMin(T &x, T y) {
    if(y < x) x = y;
}

template <typename T>
inline void swap(T &x, T &y) {
    T t = x; x = y; y = t;
}

int find(int x) {
    return ufs[x] == x ? x : ufs[x] = find(ufs[x]);
}

void dfs1(int x, int fat, int depth) {
    fa[x] = fat, dep[x] = depth, siz[x] = 1;
    int maxson = -1;
    for(int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if(y == fat) continue;
        pid[e[i].eid] = y;
        eVal[y] = e[i].val;
        dfs1(y, x, depth + 1);
        
        siz[x] += siz[y];
        if(siz[y] > maxson) 
            maxson = siz[y], son[x] = y;
    }
}

void dfs2(int x, int topf) {
    top[x] = topf, w[id[x] = ++dfsc] = eVal[x];
    if(!son[x]) return;
    dfs2(son[x], topf);
    for(int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if(y == fa[x] || y == son[x]) continue;
        dfs2(y, y);
    }
}

namespace Bit {
    ll s[N];
    
    #define lowbit(p) (p & (-p))
    
    inline void modify(int p, ll v) {
        for(; p <= n; p += lowbit(p))
            s[p] += v;
    }
    
    inline ll getSum(int p) {
        ll res = 0LL;
        for(; p > 0; p -= lowbit(p))
            res += s[p];
        return res;
    }
    
    inline ll query(int l, int r) {
        return getSum(r) - getSum(l - 1);
    }
    
} using namespace Bit;

inline ll getDis(int x, int y) {
    ll res = 0LL;
    for(; top[x] != top[y]; ) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        res += query(id[top[x]], id[x]);
        x =fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    res += query(id[x] + 1, id[y]);
    return res;
}

int main() {
    read(n), read(qn);
    for(int i = 1; i <= n; i++) ufs[i] = i;
    for(int i = 1; i <= n; i++) {
        int x, y; ll v;
        read(x), read(y), read(v);
        int fx = find(x), fy = find(y);
        if(fx != fy) {
            ufs[fx] = fy; 
            add(x, y, i, v), add(y, x, i, v);
        } else 
            sx = x, sy = y, sv = v, sid = i;
    }
    
    dfs1(1, 0, 1), dfs2(1, 1);
    
/*    for(int i = 1; i <= n; i++)
        printf("%lld\n", eVal[i]);
    printf("\n");   */
    
    for(int i = 1; i <= n; i++)
        if(w[i]) modify(i, w[i]);
    
    for(int op; qn--; ) {
        read(op);
        if(op == 1) {
            int x; ll v;
            read(x), read(v);
            if(x == sid) sv = v;
            else {
                modify(id[pid[x]], -eVal[pid[x]]);
                eVal[pid[x]] = v;
                modify(id[pid[x]], v);
            }
        } else {
            int x, y;
            read(x), read(y);
            ll res = getDis(x, y);
            chkMin(res, getDis(x, sx) + getDis(y, sy) + sv);
            chkMin(res, getDis(x, sy) + getDis(y, sx) + sv);
            printf("%lld\n", res);
        }
    }
    
    return 0;
}
View Code

 

posted @ 2018-11-01 15:45  CzxingcHen  阅读(149)  评论(0编辑  收藏  举报