1. 程式人生 > >luogu P4949 最短距離

luogu P4949 最短距離

題目描述

給出一個 N 個點 N 條邊的無向連通圖。

你需要支援兩種操作:

  1. 修改 第 x 條邊的長度為 y ;

  2. 查詢 點 x 到點 y 的最短距離。

共有 {M}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 輸出查詢的結果。

 

此題是一道基環樹上樹鏈剖分題目

思路是這樣的:基環樹其實可以看做一棵樹多連了一條邊,於是我們可以通過加邊時維護一個並查集,來找出多的那條邊。

將那條多出的邊記錄下來。

然後我們考慮u到v的最大值,有兩種情況

  u直接在樹上到v

  u,v到多出的那條邊的兩端,通過這條邊連在一起

與是我們就可以很愉快的在樹上跑樹鏈剖分了,注意此題是邊權而不是點權

那我們對於u到v權值為w的一條邊可以看做u->xx->v,u,v點權為0,xx點權為w,就可將邊權轉化為點權了,點數翻倍,記得陣列大小翻倍喲

值得一提的是我一開始線段樹的陣列忘記開4倍了,結果又WA又TLE40分,搞得我還以為哪裡寫錯了呢

實現如下:

#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
using namespace std;
typedef long long ll;
inline int read()
{
    
int a=0,p=0;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') p=1,ch=getchar(); while(ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+ch-'0',ch=getchar(); return p?-a:a; } const int N=200100; int n,q,op,u,v,w,cnt,sum[N<<2],head[N],top[N],fe[N],fa[N],id[N],dep[N],size[N],son[N],ww[N],wn[N],tim=0,t1,t2,keu,kev,kew,kex,xu; int getf(int u){return fe[u]==u?u:fe[u]=getf(fe[u]);} struct EDGE{int nxt,to;}e[N<<1]; void add(int u,int v){e[++cnt]=(EDGE){head[u],v};head[u]=cnt;} void build(int l,int r,int o) { if(l==r){sum[o]=wn[l];return;} int mid=(l+r)>>1; build(lson);build(rson); sum[o]=sum[o<<1]+sum[o<<1|1]; } void update(int pre,int val,int l,int r,int o) { if(l==r){sum[o]=val;return;} int mid=(l+r)>>1; if(pre<=mid) update(pre,val,lson); else update(pre,val,rson); sum[o]=sum[o<<1]+sum[o<<1|1]; } int query(int L,int R,int l,int r,int o) { if(L<=l&&r<=R) return sum[o]; int mid=(l+r)>>1,ans=0; if(L<=mid) ans+=query(L,R,lson); if(R> mid) ans+=query(L,R,rson); return ans; } int query_tree(int u,int v) { int ans=0; while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); ans+=query(id[top[u]],id[u],1,n,1); u=fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); return ans+query(id[u],id[v],1,n,1); } void dfs1(int u,int ff) { fa[u]=ff;dep[u]=dep[ff]+1;size[u]=1; int maxson=0; for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) if(v!=ff) { dfs1(v,u); size[u]+=size[v]; if(size[v]>maxson) maxson=size[v],son[u]=v; } } void dfs2(int u,int topf) { id[u]=++tim;top[u]=topf;wn[tim]=ww[u]; if(!son[u]) return; dfs2(son[u],topf); for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } int main() { // freopen("input","r",stdin); // freopen("output","w",stdout); xu=n=read(),q=read(); for(int i=1;i<=n;i++) fe[i]=i; for(int i=1;i<=n;i++) { u=read(),v=read(),w=read(); t1=getf(u),t2=getf(v); if(t1!=t2) { fe[t1]=t2;xu=n+i;ww[xu]=w; add(u,xu);add(xu,u); add(v,xu);add(xu,v); } else {keu=u;kev=v;kew=w;kex=i;} } n<<=1; dfs1(1,1);dfs2(1,1);build(1,n,1); int ans=0; while(q--) { op=read(),u=read(),v=read(); if(op==1) { if(u==kex) kew=v; else update(id[u+(n>>1)],v,1,n,1); } else { ans=query_tree(u,v); printf("%d\n",min(ans,kew+min(query_tree(u,keu)+query_tree(v,kev),query_tree(u,kev)+query_tree(v,keu)))); } } return 0; }