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;
}

原文地址:https://www.cnblogs.com/fht-litost/p/9557714.html

时间: 2024-10-02 11:38:20

HDU - 6393 Traffic Network in Numazu(树链剖分+基环树)的相关文章

HDU - 6393 Traffic Network in Numazu (LCA+RMQ+树状数组)

这道题相当于将这两题结合: http://poj.org/problem?id=2763 http://codeforces.com/gym/101808/problem/K 题意:有N各点N条边的带权无向图(相当于一棵树多了一条边),两种操作:修改一条边的权值:求两点间的最短路径. 分析:将任意一条边取出来,其余n-1条边可以结合LCA解最短路.询问时,比较通过取出的边和仅通过树上的边的路径的大小,最小值就是两点的最短路径. 树状数组差分维护点到根节点的距离,根据dfs序来记录需要维护的范围.

HDU 2460 Network(双连通+树链剖分+线段树)

HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链剖分+线段树处理 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #pragma comment(linke

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

HDU 3966 Aragorn&#39;s Story (树链剖分+线段树)

题意:给你一棵树,然后有三种操作 I L R K: 把L与R的路径上的所有点权值加上K D L R K:把L与R的路径上的所有点权值减去K Q X:查询节点编号为X的权值 思路:树链剖分裸题(我还没有怎么学懂,但基本已经没有什么太大的问题,主要的问题就在于点或者边对于数据结构的映射关系是,主要没有单独手写过树链剖分,所以对这部分 没有什么体会) 我们知道树链剖分是一种将树剖为链的一种算法,其思想和dfs序差不多,但根据树链剖分的性质,我们的重链是连续的区间,这样对于重链或者重链上的点我们可以方便

HDU-3966 Aragorn&#39;s Story(树链剖分+线段树)

Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 12479    Accepted Submission(s): 3331 Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lor

HDU3966 Aragorn&#39;s Story 树链剖分+线段树

区间更新,单点查询,,,,奇葩,HDU上强行加了扩栈才过. 1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 #define lson l,m,rt<<1 8 #define rson m+1,

hdu3966 树链剖分+线段树 裸题

HDU - 3966 题意:给一颗树,3种操作,Q u 查询u节点的权值,I a b c 对a到b的路径上每个点的点权增加c,D a b c 对a b 路径上所有点的点权减少c 思路:树链剖分+线段树,2个问题,第一,如果是先建树再输入点的点权,记录tip(点映射到线段树后的位置),如果先输入点权,再建树,不仅要记录tip还要记录ran(线段树上某个位置上的点对应的树上点的序号,与tip是相互映射):第二,连接起线段树和树链剖分的是get函数,区间操作才需要用到get函数,单点操作直接在线段树上

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out