【luogu4949】最短距离
题目描述
给出一个 N 个点 N 条边的无向连通图。
你需要支持两种操作:
-
修改 第 x 条边的长度为 y ;
-
查询 点 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; }
浙公网安备 33010602011771号