解題報告 FZU 2082 過路費 樹剖

2021-10-09 02:31:35 字數 1719 閱讀 2595

比較裸的樹剖,但是給的是邊權,這時候就要把每條邊的邊權下放到深度相對更深的點中。然後正常樹剖操作。單點修改就改對應邊深度深的那個點的點權,區間查詢需要判斷下:首先還是正常重邊上查詢,然後最後兩點在同一條重邊後,如果這兩個點相同的話就不用再查詢這個點的點權了,因為我們要看的實際是邊,如果不同就要少算那個深度最淺的點,所以查的是son[x]和y(或者x的dfs序+1到y)之間的點權和。

ac**:

#include #include #include #include using namespace std;

typedef long long ll;

const int maxn=5e4+10;

struct edgee[maxn<<1];

int head[maxn<<1],cnt=0;

int n;//節點數目

int d[maxn];//d[i]表示第i個結點的深度

int fa[maxn];//fa[i]表示第i個結點的parent

int son[maxn];//son[i]表示第i個結點的重子節點

int tot[maxn];//tot[i]表示以第i個結點為根節點的子樹結點個數

int top[maxn];//top[i]表示第i個結點所在重鏈的頂部節點

int idx[maxn];//idx[i]表示第i個結點對應的dfs序

ll a[maxn];//a[i]表示dfs序為i的結點的初值

ll w[maxn];//w[i]表示第i個結點的初值

int ct=0;//輔助記錄idx和a,沒啥用

int m,r;//m次詢問,r為樹的根

void add_edge(int u,int v,ll w)

struct nodetree[maxn<<2];

void pushup(int root)

void build(int root,int left,int right)

int mid=(left+right)>>1;

build(root<<1,left,mid);

build(root<<1|1,mid+1,right);

pushup(root);

}void change(int root,int k,ll val)

if(k<=tree[root<<1].right) change(root<<1,k,val);

if(k>=tree[root<<1|1].left) change(root<<1|1,k,val);

pushup(root);

}ll search(int root,int left,int right)

int dfs1(int now,int pre,int dep)

return tot[now];

}void dfs2(int now,int topf)

}ll tree_sum(int x,int y)

void init()

struct rd road[maxn];

int main()

dfs2(r,r);

build(1,1,n);

while(m--)

else

} }}/*

5 31 2 1

2 3 2

3 4 3

4 5 4

1 4 5

0 3 4

1 3 5

*/

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...

FZU2082 過路費 樹鏈剖分線段樹

如果只是查詢沒有修改就好做了,只需要找lca。加上修改操作之後可以使用樹鏈剖分 線段樹,注意把邊權下放到點權,因此需要特別注意 當我們執行lca操作時,如果u v那麼直接返回路徑長度 如果u v,則說明此時uv 假設dep u dep v 在一條重鏈上,返回的路徑長度還需要加上dis u,son v...

FZU 2082 過路費(邊剖分模板題)

link problem 2082 過路費 有n座城市,由n 1條路相連通,使得任意兩座城市之間可達。每條路有過路費,要交過路費才能通過。每條路的過路費經常會更新,現問你,當前情況下,從城市a到城市b最少要花多少過路費。有多組樣例,每組樣例第一行輸入兩個正整數n,m 2 n 50000,1 m 50...