洛谷3233 HNOI2014(虛樹 dp)

2022-05-25 14:30:09 字數 2712 閱讀 7168

膜拜一發\(mts\_246,forever\_shi\)

這兩位爺是真的無敵!

首先來看這個題,一看題目的資料範圍和「關鍵點」字眼,我們就能得知這是一道虛樹題

那就先一如既往的建出來虛樹吧

qwq但是這之後,應該怎麼去dp呢。

首先,我們需要知道在虛樹上每個點的從屬都是誰,這樣才便於我們進一步擴充套件到虛樹之外的點。

那麼怎麼求這個東西呢?我們可以先通過一編dfs,求出來子樹對父親的影響,也就是從下到上的答案(先\(dfs\)到底,再更新)

void dp1(int x,int flag)

for (int i=point[x];i;i=nxt[i]) }

}

然後呢,因為還存在說通過兄弟更新,或者子樹之外的點更新的情況,所以我們還需要重新\(dfs\)一遍,不過這次是嘗試通過用父親來更新兒子,也就是從上到下(先更新,後\(dfs\))

void dp2(int x,int flag)

dp2(p,flag);

}}

至此,我們就得到了所有虛樹上的點的\(dis\) 和 \(bel\),那怎麼擴充套件到所有點呢qwq

這裡就需要乙個奇妙的統計答案的技巧了

我們另\(ymh[i]\)表示與\(i\)相同議事處的點的個數。

首先,我們將初值弄成\(size[i]\),是i在原樹的子樹大小(這一定是不對的,因為子樹中有一些會和他的某個非直系子輩給包含,而他在上面的一片區域,也一定有和他一樣的點)

然後我們進行dfs

對於這個東西,顯然是要從下向上更新的

所以我們\(dfs\)到底,對於當前\(x->p\)這條邊,如果說兩個點的\(bel\)是相等的,我們就令\(ymh[x]-=size[p]\),相當於把原樹\(x->p\)這路徑附近部分所有的點,都給了\(x\),不論是合法還是不合法。

那麼上一種情況裡面不合法的情況,就是兩個點之間存在\(bel\)不一樣的點,也就是說,會存在一條邊\(x->p\),其中\(bel[x]!=bel[p]\),那麼這條路徑之間的東西應該怎麼算呢。

不難發現,一定是會存在說,這段路徑中間會有乙個點,以上全是屬於\(bel[x]\),以下全是屬於\(bel[p]\)的。

那麼我們可以通過倍增的方式來求出這個點(具體求的時候有一些細節,直接寫在**裡面了)

然後假設求出來的點是\(lyf\),那麼$$ymh[p]+=size[lyf]-size[p],ymh[x]-=size[lyf]$$

原理的話,和上面同理

這種用ymh陣列求解的方式,實際上就是先弄乙個初值,然後把不合法的(或者是會算重複的)減掉,然後把少算的加進去

qwq總之就是很巧妙!!!!!!!

既不會算少,也不會算重複

直接放**

#include#include#include#include#include#include#include#include#define mk makr_pair

#define ll long long

using namespace std;

inline int read()

while (isdigit(ch))

return x*f;

}const int maxn = 6e5+1e2;

const int maxm = 2*maxn;

const int inf = 1e9;

int point[maxn],nxt[maxm],to[maxm],val[maxm];

int bel[maxn],dis[maxn],f[maxn][21];

int num[maxn];

int size[maxn],deep[maxn],dfn[maxn];

int cnt,n,m;

int tot,top;

int s[maxn];

int k,a[maxn];

int ymh[maxn],tag[maxn];

int ans[maxn];

void addedge(int x,int y,int w)

void dfs(int x,int fa,int dep)

}void init()

}int go_up(int x,int d)

} return f[x][0];

} bool cmp(int a,int b)

else

else}}

}if (s[top]!=a[i]) s[++top]=a[i];

}while (top>1)

}void dp1(int x,int flag)

for (int i=point[x];i;i=nxt[i]) }

}void dp2(int x,int flag)

dp2(p,flag); }}

int up(int x,int d)

void dodo(int x)

ans[bel[p]]+=ymh[p];

} if (x==1) ans[bel[x]]+=ymh[x];

}int b[maxn];

int main()

dfs(1,0,1);

init();

memset(point,0,sizeof(point));

m=read();

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

return 0;

}

P3233 HNOI2014 世界樹(虛樹)

看到 mi 300000自然聯想到虛樹,簡單思考一下似乎可行,但剩下的部分貌似就比較麻煩。首先對重新構建的虛樹,考慮每個點應該被誰管。因為乙個點既可以被它子樹中的點管,也可以被子樹以外的點管,所以我們做兩次dfs。第一次先遍歷子節點,再更新,記錄的是乙個點子樹中最近的管他的點是誰。第二次先用從父節點...

洛谷P3237 HNOI2014 公尺特運輸

公尺特是d星球上一種非常神秘的物質,蘊含著巨大的能量。在以公尺特為主要能源的d星上,這種公尺特能源的運輸和儲 存一直是乙個大問題。d星上有n個城市,我們將其順序編號為1到n,1號城市為首都。這n個城市由n 1條單向高速 通道連線起來,構成一棵以1號城市 首部 為根的樹,高速通道的方向由樹中的兒子指向...

洛谷 2014 選課

在大學裡每個學生,為了達到一定的學分,必須從很多課程裡選擇一些課程來學習,在課程裡有些課程必須在某些課程之前學習,如高等數學總是在其它課程之前學習。現在有n門功課,每門課有個學分,每門課有一門或沒有直接先修課 若課程a是課程b的先修課即只有學完了課程a,才能學習課程b 乙個學生要從這些課程裡選擇m門...