給出乙個 n 個點 n 條邊的無向連通圖。
你需要支援兩種操作:
修改 第 x 條邊的長度為 y ;
查詢 點 x 到點 y 的最短距離。
共有 m 次操作。
思路
n個點n條邊的無向連通圖(簡單圖),如果少一條邊就是形成一棵樹,就是一道lca題,這題多了一條邊,就要用相應的方法處理這條邊。
考慮剔除的邊是(uu,vv),權值為w,那麼 (u,v) 的最短距離就是 min(dis(u,v),dis(u,uu)+dis(v,vv)+w,dis(u,vv)+dis(v,uu)+w)。
dis(u, v)=dis(root, u) + dis(root, v) - 2 * dis(root, lca(u, v))。
所以就是維護乙個dis值。
考慮到對一條邊修改,就會修改這條邊下方所有的dis的權值,所以是區間更新;查詢是單點查詢。所以用樹狀陣列維護。
又因為是樹形結構,所以用樹鏈剖分將之轉換為線性結構。思路很簡單,重要是**實現。
#include
using
namespace std;
const
int maxn =
1e5+7;
typedef
long
long ll;
ll sum[maxn]
;int n, m;
int head[maxn]
, to[maxn<<1]
, nex[maxn<<1]
, tot =
2, edge[maxn<<1]
, hid;
struct node e[maxn]
;//給每一條邊編號
void
add(
int x,
int y,
int c)
intlowbit
(int i)
void
update
(int x,
int c)
}void
update_
(int x,
int y,
int c)
ll getsum
(int x)
int dfn[maxn]
, siz[maxn]
, dep[maxn]
, son[maxn]
, cnt, fa[maxn]
, top[maxn]
;ll dis[maxn]
;bool vis[maxn]
;void
dfs1
(int x,
int f)
//hid是剔除的邊
vis[v]
=true
; e[i>>1]
.id = i;
//給邊編號,因為是鏈式前向星存圖,i/2就是該邊的編號
dis[v]
= dis[x]
+ edge[i]
;//dis記錄改點到根的距離
dfs1
(v, x)
; siz[x]
+= siz[v];if
(siz[v]
> siz[son[x]
]) son[x]
= v;}}
}void
dfs2
(int x,
int fir)
}int
lca(
int x,
int y)
return dep[x]
> dep[y]
? y : x;
}ll cal
(int u,
int v)
intmain()
;}vis[1]
=true
;dfs1(1
,0);
dfs2(1
,1);
for(
int i =
1; i <= n; i++
)update_
(dfn[i]
, dfn[i]
, dis[i]);
while
(m--
)int dy = y - e[x]
.z;//這裡又是乙個轉換思想,修改權值等於增加差值
e[x]
.z = y;
update_
(dfn[to[e[x]
.id]
], dfn[to[e[x]
.id]
]+ siz[to[e[x]
.id]]-
1, dy)
;//區間修改要用差分思想,更新區間是該點和它的子樹
}else
}}
luogu P4949 最短距離
給出乙個 n 個點 n 條邊的無向連通圖。你需要支援兩種操作 修改 第 x 條邊的長度為 y 查詢 點 x 到點 y 的最短距離。共有 m 次操作。輸入格式 輸入共 n m 1 行 第 1 行,包含 2 個正整數 n,m,表示點數即邊數,操作次數。第 2 行到第 n 1 行,每行包含 3 個正整數 ...
1407 最短距離
兩個點 a b 均在做勻速直線運動。給出 t 0時刻 a b 的座標,以及 a b 的速度,計算t 0時兩個點的距離的最小值。輸入的第一行包含乙個整數 t 1 t 200 表示一共有 t 組測試資料。對於每組測試資料,第一行包含4個整數 x a y a v ax v ay 103 x a y a v...
編輯最短距離
給定兩個字串s和t,對於t我們允許三種操作 1 在任意位置新增任意字元 2 刪除存在的任意字元 3 修改任意字元 問最少操作多少次可以把字串t變成s?例如 s abcf t dbfg 那麼我們可以 1 把d改為a 2 刪掉g 3 加入c 所以答案是3。1 把t中字元全刪了,再新增s的全部字元,操作次...