bzoj 世界樹 虛樹 樹形DP lca

2021-08-19 08:44:50 字數 2885 閱讀 6421

#include #include #include #include #include #define inf 0x3f3f3f3f

#define rep0(i, n) for (int i = 0; i < n; i++)

#define rep1(i, n) for (int i = 1; i <= n; i++)

#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)

#define rep_1(i, n) for (int i = n; i > 0; i--)

#define max(x, y) (((x) > (y)) ? (x) : (y))

#define min(x, y) (((x) < (y)) ? (x) : (y))

#define mem(x, y) memset(x, y, sizeof(x))

#define maxn 300010

#define maxl 20

using namespace std;

typedef long long ll;

typedef pairpp;

struct edge

edges[maxn * 2];

int head[maxn], tot, n, q, pa[maxn][maxl], sz[maxn], dep[maxn];

int clc[maxn], cl, bk[maxn];

int qu[maxn], tail, qu0[maxn];

int st[maxn], top, root;

pp nbr[maxn];

int ans[maxn];

bool cmp(int x, int y)

void dfs(int u, int fa, int d)

sz[u] = cnt; //預處理出子樹size

}void init()}}

}void addedge(int u, int v) // 單向加邊建虛樹 加速

int lca(int a, int b)

if (a == b)

return a;

for (int k = maxl - 1; k >= 0; k--)

return pa[a][0];

}void build()

else

if (dep[fa] < dep[root]) // 建立的虛樹上不一定有1節點 需要求深度最小的節點作為root

if (top && dep[st[top - 1]] > dep[fa]) // 如果lca不在棧中 先清空fa的鄰接表資訊後加邊

else if (!top)

st[top++] = u;}}

for (int i = 0; i < top - 1; i++)

addedge(st[i], st[i + 1]);

}void dp(int u, int fa) //第一遍樹形dp求各節點子樹範圍內 與距離最近點的 距離

else if (dis == nbr[v].second + dep[v] - dep[u] && nbr[v].first < tmp) // 有兩個相同距離點的情況

}if (bk[u] != q)

}void dp1(int u, int fa) // 第二次dp求父親節點範圍內 的距離

ans[nbr[u].first]++; // 求出最近點後直接計數

}else if (bk[u] != q)

ans[nbr[u].first]++;

for (int i = head[u]; i; i = edges[i].nxt)

}int solve(int u, int fa) // 第三次搜尋 求不在虛樹內的節點的最近節點

else

for (int k = maxl - 1; k >= 0; k--)

ans[nbr[u].first] += sz[v] - sz[u];

//cnt = sz[v];

v1 = v;

step = dep[v] - dep[fa] - 1;

if (step > 0)

for (int k = maxl - 1; k >= 0; k--)

cnt = sz[v1];

if (nbr[u].first != nbr[fa].first)

ans[nbr[fa].first] += sz[v1] - sz[v];

}else if (fa < 0 && u != 1) // root可能不是1 此時要單獨計數root父節點範圍內的節點數

int tmp = 1;

for (int i = head[u]; i; i = edges[i].nxt)

ans[nbr[u].first] += sz[u] - tmp; // 樹上的點上可能有 不在虛樹內的子節點

return cnt; // 虛樹節點 -> 虛樹子節點 乙個子樹方向 原樹內的真實節點數

}int main()

init();

scanf("%d", &q);

while (q)

sort(qu, qu + tail, cmp);

root = qu[0];

build();

dp(root, -1);

dp1(root, -1);

solve(root, -1);

printf("%d", ans[qu0[0]]);

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

printf("\n");

q--;

}return 0;

}

世界樹 虛樹,坑

坑了四天的虛樹,終於過了,也對treedp印象深刻了些,這裡挖個坑 基環樹dp,該搞搞了 坑點1 兩個點直接要的不僅僅的路徑長度,而是路徑上的所有點,那麼應該是兒子數相減 坑點2 兩個點在st表查詢的時候可能會超邊界,因為mid不一定在鏈上 坑點3 找某個點屬於哪個點歸屬的時候,更新必須加入佇列中,...

bzoj2286 消耗戰 虛樹 樹形dp

解題思路 假如只有一次詢問,可以很好想到樹形dp方程 如果u是關鍵點,則f u w fa u u 如果u不是關鍵點,則f u min w fa u u f son u 但這樣一次複雜度為o n 則總複雜度為o nm 顯然超時。像這種每次詢問都給出多個關鍵點的題,應該建虛樹,即每次詢問都只把關鍵點及其...

BZOJ2286 消耗戰(虛樹,樹形dp)

今天本tu生日,學個新演算法慶祝一下。學了虛樹,碰到每次詢問給你一些點點的樹就不虛了 對於一棵樹,我們可以在上面用我們學過的演算法為所欲為。假設題目有多個詢問,每個詢問給出了一些點,那我們可以把這些點和及有關係的點拉出來,合併點和邊的資訊,構出虛樹,在虛樹上繼續為所欲為。對於與詢問有關係的點,就是這...