【luogu4949】最短距离

题目描述

给出一个 N 个点 N 条边的无向连通图。

你需要支持两种操作:

  1. 修改 第 x 条边的长度为 y ;

  2. 查询 点 x 到点 y 的最短距离。

共有 M 次操作。


输入

输入共 N + M + 1 行:

第 1 行,包含 2 个正整数 N,M,表示点数即边数,操作次数。

第 2 行到第 N + 1 行,每行包含 3 个正整数 x,y,z,表示 x 与 y 间有一条长度 为 z 的边。

第 N + 2 到 N + M + 1 行,每行包含 3 个正整数 opt,x,y,表示操作种类,操作的参数(含义见【题目描述】)。


输出

对于每次操作 2 输出查询的结果。


样例输入

4 5
1 2 11
1 3 12
2 3 13
1 4 15
2 2 3
1 2 1
2 2 3
2 2 4
2 3 4


样例输出

13
12
26
16

 

 



题解

 

参考三点通信,其实这两道题是类似的。

先找n-1条边树剖,对于剩下的那条边,求最短距离时可以使用也可以不使用,两种情况取min即可。

复杂度O(nlog2n) 。建议用树状数组维护距离。

 

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=2e5+500;
const int maxm=4e5+50;

int n,m,cnt,U,V,E;
int fir[maxn],nex[maxm],to[maxm],from[maxm],ecnt;
int son[maxn],fa[maxn],top[maxn],dep[maxn],sz[maxn],id[maxn];
ll wi[maxn],val[maxn],wt[maxn];
bool vis[maxn];

inline void add(int u,int v,int w){
    nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;wi[ecnt]=w;from[ecnt]=u;
}

struct SegmentTree{ll v,l,r;}st[maxn<<2];

inline void pushup(int root){
    st[root].v=st[root<<1].v+st[root<<1|1].v;
}

void build(int root,int l,int r){
    st[root].l=l;st[root].r=r;
    if(l==r) st[root].v=wt[l];
    else{
        int m=l+r>>1;
        build(root<<1,l,m);build(root<<1|1,m+1,r);
        pushup(root);
    }
}

inline void chg(int root,int x,ll val){
    if(st[root].l==st[root].r) st[root].v=val;
    else{
        int m=st[root].l+st[root].r>>1;
        if(x<=m) chg(root<<1,x,val);
        else chg(root<<1|1,x,val);
        pushup(root);
    }
}

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

inline ll Qry(int x,int y){
    int f1=top[x],f2=top[y];ll ans=0;
    while(f1!=f2){
        if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
        ans+=query(1,id[f1],id[x]);
        x=fa[f1],f1=top[x];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans+=query(1,id[x]+1,id[y]);
    return ans;
}

void dfs1(int x,int f,int deep){
    fa[x]=f;
    dep[x]=deep;
    sz[x]=1;
    vis[x]=false;
    for(int e=fir[x];e;e=nex[e]){
        int v=to[e];
        if(v==f) continue;
        if(!vis[v]){
            U=x;V=v;E=e;continue;
        }
        val[v]=wi[e];
        dfs1(v,x,deep+1);
        sz[x]+=sz[v];
        if(sz[v]>sz[son[x]]) son[x]=v;
    }
}

void dfs2(int x,int topf){
    top[x]=topf;
    id[x]=++cnt;
    wt[cnt]=val[x];
    if(!son[x]) return ;
    dfs2(son[x],topf);
    for(int e=fir[x];e;e=nex[e]){
        int v=to[e];
        if(v==fa[x]||v==son[x]||(U==x&&V==v)||(U==v&&V==x)) continue;
        dfs2(v,v);
    }
}

template<typename T>inline void read(T& aa){
    char cc; ll ff;aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}

int main(){
    memset(vis,true,sizeof(vis));
    read(n),read(m);
    for(int i=1;i<=n;i++){
        int x,y,z;
        read(x),read(y),read(z);
        add(x,y,z);add(y,x,z);
    }
    dfs1(1,0,1);dfs2(1,1);build(1,1,n);
    while(m--){
        int op,x,y;
        read(op),read(x),read(y);
        if(op==1){
            int Edge=x*2;
            int u=from[Edge],v=to[Edge];
            if(dep[u]>dep[v]) swap(u,v);
            if((U==u&&V==v)||(U==v&&V==u)) wi[E]=(ll)y;
            else chg(1,id[v],(ll)y);
        }
        else{
            ll ans=Qry(x,y);
            ans=min(ans,Qry(U,x)+Qry(y,V)+wi[E]);
            ans=min(ans,Qry(V,x)+Qry(y,U)+wi[E]);
            printf("%lld\n",ans);
        }
    }
    return 0;
} 

 

posted @ 2018-10-29 20:01  rld  阅读(182)  评论(0)    收藏  举报