如果只是查詢沒有修改就好做了,只需要找lca。
加上修改操作之後可以使用樹鏈剖分+線段樹,注意把邊權下放到點權,因此需要特別注意:當我們執行lca操作時,如果u = v那麼直接返回路徑長度;如果u ≠ v,則說明此時uv(假設dep[u]>dep[v])在一條重鏈上,返回的路徑長度還需要加上dis(u,son[v])(son[v]是v的重兒子)。
#include#include#include#define maxn 50010
using namespace std;
struct edge
edge[maxn*2];
int cnt,head[maxn];
void add_edge(int u,int v)
int e[maxn][3];
int n,m,x,y,z;
int dep[maxn],htp[maxn],fa[maxn],sz[maxn],son[maxn];
int dcnt,tid[maxn],rnk[maxn];
void dfs1(int u,int f)
}void dfs2(int u,int tp)
}struct tr
tree[maxn];
void build_tree(int i,int l,int r)
int mid = (l+r)/2;
build_tree(i*2,l,mid);
build_tree(i*2+1,mid+1,r);
}void update(int i,int pos,int val)
int mid = (tree[i].l+tree[i].r)/2;
if(pos <= mid) update(i*2,pos,val);
else update(i*2+1,pos,val);
tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;
}int query(int i,int l,int r)
int mid = (tree[i].l+tree[i].r)/2;
if(r <= mid) return query(i*2,l,r);
else if(l > mid) return query(i*2+1,l,r);
else return query(i*2,l,mid)+query(i*2+1,mid+1,r);
}int change(int u,int v)
if(u == v) return sum;
if(dep[u] < dep[v]) swap(u,v);
return sum + query(1,tid[son[v]],tid[u]);
}void init()
int main()
dfs1(1,-1);
dfs2(1,1);
build_tree(1,1,n);
for(int i = 1; i < n; i++)
for(int i = 1; i <= m; i++)
}}
fzu 2082 過路費(樹鏈剖分)
思路 樹鏈剖分的裸題了 include include include include define ll long long using namespace std const int maxn 50000 100 int siz maxn fa maxn son maxn dep maxn to...
解題報告 FZU 2082 過路費 樹剖
比較裸的樹剖,但是給的是邊權,這時候就要把每條邊的邊權下放到深度相對更深的點中。然後正常樹剖操作。單點修改就改對應邊深度深的那個點的點權,區間查詢需要判斷下 首先還是正常重邊上查詢,然後最後兩點在同一條重邊後,如果這兩個點相同的話就不用再查詢這個點的點權了,因為我們要看的實際是邊,如果不同就要少算那...
FZU 2082 過路費(邊剖分模板題)
link problem 2082 過路費 有n座城市,由n 1條路相連通,使得任意兩座城市之間可達。每條路有過路費,要交過路費才能通過。每條路的過路費經常會更新,現問你,當前情況下,從城市a到城市b最少要花多少過路費。有多組樣例,每組樣例第一行輸入兩個正整數n,m 2 n 50000,1 m 50...