ACM春季集訓樹上問題

2022-05-25 13:12:07 字數 3482 閱讀 3954

感覺樹上問題的難度真的好大啊

lca,倍增,生成樹,樹鏈剖分,唉好難

下面這道題寫了好長時間,就是樹鏈剖分+lca,我寫了兩種方法不知道為什麼有一種是re和mle了

真的好痛苦,調了好久的bug還沒有調出來,emmmm我尋思問問大佬們了,希望斧正一下我的**

在給出**之前看了網課(洛谷的啦),emmm尋思總結一下嘍:

1,將樹從x到y結點最短路徑上所有節點的值都加上z

這也是個模板題了吧

我們很容易想到,樹上差分可以以o(n+m)的優秀複雜度解決這個問題

2,求樹從x到y結點最短路徑上所有節點的值之和

lca大水題,我們又很容易地想到,dfs o(n)預處理每個節點的dis(即到根節點的最短路徑長度)

然後對於每個詢問,求出x,y兩點的lca,利用lca的性質 distance (x,y)=dis(x)+dis(y)-2*dis(lca) 求出結果

時間複雜度o(mlogn+n)

現在來思考乙個bug:

如果剛才的兩個問題結合起來,成為一道題的兩種操作呢?

剛才的方法顯然就不夠優秀了(每次詢問之前要跑dfs更新dis)

樹剖是通過輕重邊剖分將樹分割成多條鏈,然後利用資料結構來維護這些鏈(本質上是一種優化暴力)

const

int maxn=1e5+10

;struct

edgee[

2*maxn];

struct

nodenode[

2*maxn];

int rt,n,m,r,a[maxn],cnt,head[maxn],f[maxn],d[maxn],size[maxn],son[maxn],rk[maxn],top[maxn],id[maxn];

名稱解釋f[u]儲存結點u的父親節點d[u]儲存結點u的深度值size[u]儲存以u為根的子樹節點個數son[u]儲存重兒子

rk[u]儲存當前dfs標號在樹中所對應的節點top[u]儲存當前節點所在鏈的頂端節點id[u]儲存樹中每個節點剖分以後的新編號(dfs的執行順序)

void dfs1(int u,int fa,int depth)    //

當前節點、父節點、層次深度}//

進入dfs1(root,0,1);

void dfs2(int u,int t)    //

當前節點、重鏈頂端

}

回顧上文的那個題目,修改和查詢操作原理是類似的,以查詢操作為例,其實就是個lca,不過這裡使用了top來進行加速,

因為top可以直接跳轉到該重鏈的起始結點,輕鏈沒有起始結點之說,他們的top就是自己。需要注意的是,每次迴圈只能跳

一次,並且讓結點深的那個來跳到top的位置,避免兩個一起跳從而插肩而過。

int sum(int x,int

y)

else

}//迴圈結束,兩點位於同一重鏈上,但兩點不一定為同一點,所以我們還要統計這兩點之間的貢獻

if(id[x]<=id[y])

ans+=query(id[x],id[y],rt);

else

ans+=query(id[y],id[x],rt);

return

ans;

}

題目傳送門:

看完上面的解釋,這道題的思路就有了:

首先,如果每次詢問都只有兩個點,這個問題就很簡單,只要是樹上的路徑上的點就可以,尋找樹上的路徑其實就是尋找lcalca的過程。

這可以啟發我們對於三個點的情況的思考。

如果這裡有三個點,我們來認真的思考一下。經過上一問的啟發,我們來思考一下能不能運用lcalca來解決這道題。

我們可以發現,樹上三個點的三對lcalca一定有兩個是相同的。這是一件想想的話比較顯然的事情。必然能夠找到某個節點,讓三個點中

的兩個在一側,乙個在另一側。而這個點就是兩個公共的lcalca。思考的再深入些(並且結合瞎矇),我們會發現這個相同的lcalca肯

定是深度最小的乙個lcalca。

這裡,我們首先可以顯而易見的發現,這個點必須在三個點互相通達的路徑上。

我們再思考一下lcalca與路徑和的關係。假設我們知道aa和bb的lcalca是xx,而且xx是上述的3個lcalca中深度最大的那個,那麼可

以發現從xx到aa的距離加上從xx到bb的距離一定是最小的。根據上面的結論,我們知道aa,cc和bb,cc的lcalca點yy一定在乙個點上,

而且這個yy一定比xx深度小。

那麼這個時候,我們會發現此時aa,bb,cc到xx的距離和是最小的。證明的話可以這麼想:如果x'x′比xx高,那麼雖然cc到xx的距離減小了

ww,但是aa,bb到x'x′的距離均增大了ww,顯然距離和增大。如果x'x′比xx低,有乙個節點到x'x′的距離減小了ww,剩下兩個節點到x'x′的距

離均增大了ww,顯然距離和也增大。

所以我們就找到了到三個點距離和最小的點:這三個點的三對lcalca中,深度大的那兩個lca就是答案。

我們在求lcalca之前,可以先預處理出深度depdep,那麼從節點uu到vv的路徑長度就是dis = dep[u] + dep[v] - 2*dep[lca(u,v)]dis=dep[u]+dep[v]−2∗dep[lca(u,v)]。

運用這個式子分別算出aa,bb,cc到a1a1,b1b1,c1c1(三個lcalca)的距離,最後發現總的disdis居然是輪換式:

ans = dep[a]+dep[b]+dep[c]-dep[a1]-dep[b1]-dep[c1]ans=dep[a]+dep[b]+dep[c]−dep[a1]−dep[b1]−dep[c1]

ac**:

#include#include

#define n 500010

#define rg register

using

namespace

std;

intn,m,tot,last[n],dep[n],son[n],size[n],fa[n],top[n];

struct

edgee[n

<<1

];inline

intread()

inline

void add(int x,int

y); last[x]=tot;

}void dfs1(intx)}

void dfs2(int x,int

tp)inline

int lca(int x,int

y)

return dep[x]x:y;

}int

main()

dfs1(

1); dfs2(1,1

);

for(rg int i=1;i<=m;i++)

if(dep[l2]>=dep[l1]&&dep[l2]>=dep[l3])

if(dep[l3]>=dep[l1]&&dep[l3]>=dep[l2])

}return0;

}

ACM 集訓總結

include include include include using namespace std define maxn 220000 struct set int find int x void set int x a,b struct array int get int x f int a...

ACM暑假集訓

出自 南昌理工學院acm集訓隊 什麼是母函式?生成函式即母函式,是組合數學中尤其是計數方面的乙個重要理論和工具。完全看不懂,話說要不因為做了杭電的1028,完全不會去用,好像母函式還有這幾種來著,l級數 貝爾級數和狄利克雷級數 這裡我就說說普通母函式吧 其他的我也不懂 母函式的思想很簡單 就是把離散...

ACM寒假集訓

出自 南昌理工學院acm集訓隊 什麼是dfs?void dfs 狀態 a 1.判斷狀態是否合法。合法繼續執行,否則則回到上次呼叫 2.先下走一層,也就是呼叫dfs a void dfs 引數用來表示狀態 if 越界或者是不合法狀態 return if 特殊狀態 剪枝 return for 擴充套件方...