Traffic Network in Numazu

题目描述

Chika is elected mayor of Numazu. She needs to manage the traffic in this city. To manage the traffic is too hard for her. So she needs your help. You are given the map of the city —— an undirected connected weighted graph with N nodes and N edges, and you have to finish Q missions. Each mission consists of 3 integers OP, X and Y. When OP=0, you need to modify the weight of the Xth edge to Y. When OP=1, you need to calculate the length of the shortest path from node X to node Y.

输入

The first line contains a single integer T, the number of test cases. Each test case starts with a line containing two integers N and Q, the number of nodes (and edges) and the number of queries. (3≤N≤105)(1≤Q≤105) Each of the following N lines contain the description of the edges. The ith line represents the ith edge, which contains 3 space-separated integers ui, vi, and wi. This means that there is an undirected edge between nodes ui and vi, with a weight of wi. (1≤ui,vi≤N)(1≤wi≤105) Then Q lines follow, the ith line contains 3 integers OP, X and Y. The meaning has been described above.(0≤OP≤1)(1≤X≤105)(1≤Y≤105) It is guaranteed that the graph contains no self loops or multiple edges.

输出

For each test case, and for each mission whose OP=1, print one line containing one integer, the length of the shortest path between X and Y.

样例输入

2 5 5 1 2 3 2 3 5 2 4 5 2 5 1 4 3 3 0 1 5 1 3 2 1 5 4 0 5 4 1 5 1 5 3 1 2 3 1 3 2 3 4 4 4 5 5 2 5 5 0 1 3 0 4 1 1 1 4

样例输出

5 6 6 6


基环树

N个点 但是有N条边 所以一定成环
简单地讲就是树上在加一条边
处理上分为树的处理和环的处理

参考 https://www.cnblogs.com/cly-none/p/9314812.html

本题先用并查集维护,找到那个环,将环中的任意一条边去掉 就成为树了。树可以用LCA+树状数组&树上差分处理,环就直接特判就好了。三条路,一个是只走树,一个是走到X再到Y再到v,一个是走到Y再到X再到u。

LCA

求最近公共祖先的模板

//+ DFS
void dfs(ll u,ll fa){//dfs建树
    dep[u]=dep[fa]+1;
    f[u][0]=fa;//初始化每个点的父节点
    L[u]=++dfs_clock;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(v!=fa){
            G[e[i].id]=v;
            dfs(v,u);
        }
    }
    R[u]=dfs_clock;
}
//+ 初始化
void rmq_init(int n)
{
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++)
           if(f[i][j-1]) f[i][j] = f[f[i][j-1]][j-1];
}
//+ lca&rmq
int lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);//深度深的先处理
    for(int i=19;i>=0;i--){
        if(dep[u]>=dep[v]+(1<<i)){
            u = f[u][i];
        }
    }
    if(u==v){//跳到同一深度判断是否完成
        return u;
    }
    for(int i=19;i>=0;i--){//一起跳
        if(f[u][i]!=f[v][i]){
            u=f[u][i];
            v=f[v][i];
        }
    }
    return f[u][0];
}
时间戳

dfs_clock 顾名思义就是遍历到该点的时间。
R[ ]记录着访问该点的时间点 L[ ]记录着该点最深的子节点的时间点。这样处理利于树状数组。

树状数组

修改时支持对该区间前缀和的修改

距离

前缀和已经维护好了 所以两点最短距离就是两点的前缀和的和减去2倍的父节点的前缀和

#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
typedef long long ll;
struct Edge{
    int v,next,id;
}e[maxn<<1];
int n,a[maxn],head[maxn],dep[maxn<<1],cnt,pos[maxn],dfs_seq[maxn<<1],dfn,f[maxn<<1][20];
int L[maxn],R[maxn],dfs_clock,G[maxn];
ll W[maxn],C[maxn];
inline void add(int u,int v,int id){
    cnt++;
    e[cnt].v=v;
    e[cnt].next=head[u];
    e[cnt].id=id;
    head[u]=cnt;
}
inline int lowbit(int x){return (x)&(-x);}
void init(){
    memset(head,0,sizeof(head));
    memset(C,0,sizeof(C));
    memset(dep,0,sizeof(dep));
    cnt=0;
    dfs_clock=0;
}
void dfs(ll u,ll fa){//dfs建树
    dep[u]=dep[fa]+1;
    f[u][0]=fa;//初始化每个点的父节点
    L[u]=++dfs_clock;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(v!=fa){
            G[e[i].id]=v;
            dfs(v,u);
        }
    }
    R[u]=dfs_clock;
}
void rmq_init(int n)
{
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++)
           if(f[i][j-1]) f[i][j] = f[f[i][j-1]][j-1];
}
int lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);//深度深的先处理
    for(int i=19;i>=0;i--){
        if(dep[u]>=dep[v]+(1<<i)){
            u = f[u][i];
        }
    }
    if(u==v){//跳到同一深度判断是否完成
        return u;
    }
    for(int i=19;i>=0;i--){//一起跳
        if(f[u][i]!=f[v][i]){
            u=f[u][i];
            v=f[v][i];
        }
    }
    return f[u][0];
}
inline void update(int i,ll x)
{
    for(;i<=n;i+=lowbit(i)) C[i]+=x;
}
inline ll sum(int i)
{
    ll s=0;
    for(;i>0;i-=lowbit(i)) s+=C[i];
    return s;
}
inline ll dist(int u,int v)
{
    return sum(L[u])+sum(L[v])-2*sum(L[lca(u,v)]);
}
int main()
{
    int i,u,v,k,q,T;
    ll w;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&q);
        init();
        for(i=1;i<=n-1;++i){
            scanf("%d%d%lld",&u,&v,&w);
            add(u,v,i);
            add(v,u,i);
            W[i]=w;
        }
        dfs(1,0);
        rmq_init(n);
        int X,Y; ll Z;
        scanf("%d%d%lld",&X,&Y,&Z);
        W[n] = Z;
        for(i=1;i<n;++i){
            update(L[G[i]],W[i]);
            update(R[G[i]]+1,-W[i]);
        }
        while(q--){
            scanf("%d",&k);
            if(k==0){
                scanf("%d%lld",&u,&w);
                if(u==n)
                    W[n] = w;
                else{
                    update(L[G[u]],w-W[u]);
                    update(R[G[u]]+1,-w+W[u]);
                    W[u]=w;
                }
            }
            else{
                scanf("%d%d",&u,&v);
                ll ans=dist(u,v);
                ans=min(ans,dist(u,X)+dist(v,Y)+Z);
                ans=min(ans,dist(u,Y)+dist(v,X)+Z);
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}