bzoj3697 採藥人的路徑 點分治

2021-08-03 23:40:11 字數 1540 閱讀 2451

一道拖了很久的點分治,現在把他搞定了。

來自出題人hta的題解:

本題可以考慮樹的點分治。問題就變成求過根滿足條件的路徑數。

路徑上的休息站一定是在起點到根的路徑上,或者根到終點的路徑上。

如何判斷一條從根出發的路徑是否包含休息站?只要在dfs中記錄下這條路徑的和x,同時用個標誌陣列判斷這條路徑是否存在字首和為x的節點。

這樣我們列舉根節點的每個子樹。用f[i][0…1],g[i][0…1]分別表示前面幾個子樹以及當前子樹和為i的路徑數目,0和1用於區分路徑上是否存在字首和為i的節點。那麼當前子樹的貢獻就是f[0][0] * g[0][0] + σf [i][0] * g [-i][1] + f[i][1] * g[-i][0] + f[i][1] * g[-i][1],其中i的範圍[-d,d],d為當前子樹的深度。

其實這個式子挺好理解的,就是所有的可能性組合起來,注意一下g要把f的數值加上,然後f清空一下,不然會影響到後面。

#include

#include

#include

#include

#define fo(i,a,b) for(int i=a;i<=b;i++)

#define fd(i,a,b) for(int i=a;i>=b;i--)

using

namespace

std;

const

int n=1e6+5;

int n,m;

int head[n],go[n],dis[n],next[n],val[n],f[n];

int son[n];

int len,sum,tot,root,mxdep,dep[n],t[n];

bool vis[n];

typedef

long

long ll;

ll ans,f[n][2],g[n][2];

inline

int read()

while (ch<='9'&&ch>='0')

return x*f;

}inline

void add(int x,int y,int z)

inline

void getroot(int x,int fa)

} //printf("%d\n",x);

f[x]=max(f[x],sum-son[x]);

if (f[x]inline

void dfs(int x,int fa)

}t[dis[x]]--;

}inline

void work(int x)}}

fo(i,n-mx,n+mx)

g[i][0]=g[i][1]=0;

for(int i=head[x];i;i=next[i])

}}int main()

sum=f[0]=n;

getroot(1,0);

work(root);

printf("%lld\n",ans);

return

0;}

BZOJ3697 採藥人的路徑

給定一棵樹,找一些路徑滿足,路徑上0,1數量相等,並在路徑上找到乙個點 休息站 改點到路徑兩端上0,1數量也相等,同一條路徑點不同,記為不同,詢問有多少條路徑滿足條件 點分治 對於乙個點 u 我們遍歷每棵子樹中的節點 v,求出di s u,v 我們記錄這條路徑上有無節點 t 使得di s v,t 0...

bzoj3697 採藥人的路徑

這是個思路題,對我這樣的zz 來說可能已經接近自己想出來的極限了。一看統計符合條件的路徑條數,肯定是點分治,而且肯定是靜態的。首先把邊權變成 1 和 1 那麼一條路徑陰陽平衡也就是說它的權值和等於 0 根據點分治的過程,可知重心和路徑是一對多的關係,而且一條路徑只會對應乙個重心,就是說每條路徑都只會...

bzoj3697 採藥人的路徑

description 採藥人的藥田是乙個樹狀結構,每條路徑上都種植著同種藥材。採藥人以自己對藥材獨到的見解,對每種藥材進行了分類。大致分為兩類,一種是陰性的,一種是陽性的。採藥人每天都要進行採藥活動。他選擇的路徑是很有講究的,他認為陰陽平衡是很重要的,所以他走的一定是兩種藥材數目相等的路徑。採藥工...