HDU - 6393 Traffic Network in Numazu(树链剖分+基环树)

http://acm.hdu.edu.cn/showproblem.php?pid=6393

题意

给n个点和n条边的图,有两种操作,一种修改边权,另一种查询u到v的最短路。

分析

n个点和n条边,实际上是一棵树+一个环,如果仅仅是一棵树,那么这题就是树链剖分的模板题了。

对于环来说,可以考虑先把环中一条边提取出来,然后树链剖分,修改时用线段树,单点修改和区间求和。

查询时就考虑三种情况,u走树上到v,从u经过提取出来的边再到v(两种),取最小值。

至于取出环上一条边,用并查集搞搞。

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;

struct side {
    int u,v,w;
    int ne;
} s[maxn];

struct edge {
    int l,r;
    ll v;
} e[maxn<<2];

int n,q;
int head[maxn],len;
int val[maxn],hold[maxn],pre[maxn];
int deep[maxn],fa[maxn],ve[maxn],son[maxn],top[maxn],p[maxn],fp[maxn],sz;

void add(int u,int v,int w) {
    s[len].u = u;
    s[len].v = v;
    s[len].w = w;
    s[len].ne = head[u];
    head[u] = len++;
}

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

void dfs1(int u,int p,int d) {
    deep[u] = d;
    fa[u] = p;
    ve[u] = 1;
    son[u] = -1;
    for(int i = head[u]; i!= -1; i = s[i].ne) {
        if(s[i].v == p) continue;
        val[s[i].v] = s[i].w; //把边权值赋给相连的点
        hold[i>>1] = s[i].v;//这条边的权值被哪个点掌握着
        dfs1(s[i].v,u,d+1);
        ve[u]+= ve[s[i].v];
        if(son[u] == -1||ve[s[i].v]> ve[son[u]])
            son[u] = s[i].v;
    }
    return ;
}

void dfs2(int u,int sp) {
    top[u] = sp;
    p[u] = ++sz;
    fp[p[u]] = u;
    if(son[u] == -1) return ;
    dfs2(son[u],sp);
    for(int i = head[u]; i!= -1; i = s[i].ne) {
        if(s[i].v == son[u]||s[i].v == fa[u]) continue;
        dfs2(s[i].v,s[i].v);
    }
    return ;
}

void build(int i,int l,int r) {
    e[i].l = l;
    e[i].r = r;
    if(l == r) {
        e[i].v = val[fp[l]];
        return ;
    }

    int mid = (l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    e[i].v = e[i<<1].v+e[i<<1|1].v;
}

void modify(int i,int pos,int v) {
    if(pos> e[i].r||pos< e[i].l) return ;
    if(e[i].l == e[i].r) {
        e[i].v = v;
        return ;
    }
    modify(i<<1,pos,v);
    modify(i<<1|1,pos,v);
    e[i].v = e[i<<1].v+e[i<<1|1].v;
}

ll query(int i,int l,int r) {
    if(e[i].r< l||e[i].l> r) return 0;
    if(e[i].l>= l&&e[i].r<= r) return e[i].v;
    return query(i<<1,l,r)+query(i<<1|1,l,r);
}

ll demand(int x,int y) {
    int fx = top[x];
    int fy = top[y];
    ll ans = 0;
    while(fx!= fy) {
        if(deep[fx]< deep[fy]) {
            swap(fx,fy);
            swap(x,y);
        }
        ans+= query(1,p[fx],p[x]);
        x = fa[fx];
        fx = top[x];
    }
    if(x == y) return ans;
    if(deep[x]> deep[y]) swap(x,y);
    ans+= query(1,p[son[x]],p[y]);
    return ans;
}

void init() {
    sz = len = 0;
    mem(head,-1);
    for(int i = 0; i<= n; i++) pre[i] = i;
}

int main() {
    int t;
    cin>>t;

    while(t--) {
        int su,sv,sc,ss;
        scanf("%d %d",&n,&q);
        init();
        for(int i = 1; i<= n; i++) {
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            int fx = find(u);
            int fy = find(v);

            if(fx == fy) {
                len+= 2;
                ss = i;
                su = u;
                sv = v;
                sc = w;
                continue;
            } else
                pre[fy] = fx;
            add(u,v,w);
            add(v,u,w);
        }

        dfs1(1,-1,1);
        dfs2(1,1);

        build(1,1,n);

        while(q--) {
            int o,x,y;
            scanf("%d %d %d",&o,&x,&y);
            if(o == 0) {
                x--;
                if(x == ss) {
                    sc = y;
                    continue;
                }
                modify(1,p[hold[x]],y);
            } else {
                ll ans;
                ans = sc+min(demand(x,su)+demand(y,sv),demand(x,sv)+demand(y,su));
                ans = min(ans,demand(x,y));
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fht-litost/p/9557714.html