點分治 bzoj3697 採藥人的路徑

2021-09-23 20:47:57 字數 1993 閱讀 2395

【bzoj3697】採藥人的路徑

題意:有每條邊有一種屬性(陰/陽)求有多少條路徑陰=陽,且能找到乙個休息點使得起點到休息點,休息點到終點陰陽平衡.

分析:本題中邊權為0/1代表陰陽,不妨將0轉化成-1,這樣若一條路徑陰陽平衡,那麼其路徑長度即為0.

點分治。

那麼要解決的問題就是如何計算經過當前根節點有多少合法路徑。

乙個乙個子樹處理

處理當前子樹時,對於當前子樹中的乙個點,其到根的路徑長度為x,則之前的子樹中的路徑長度需要是-x,才滿足第乙個條件。如何判斷是否有休息點呢。

假設當前根為root,之前子樹中的乙個點x,當前子樹中的乙個點y,dis表示到根的路徑長。

則x-y的路徑為x–root–y

長度為dis[x]+dis[y];

現已知dis[x]+dis[y]=0;

那麼假設有乙個休息點z(z!=y,z!=root),在root–y的路徑中

故dis[x]+dis[z]=0,dis[z]=-dis[x]=dis[y];

所以當存在dis[z]=dis[y] (z!=y,z!=root)是就有乙個在root–y的路徑中的休息點z了

x–root同理

設定兩個陣列g[i][0/1],f[i][0/1];

g[i][0]表示已近處理過的子樹中的點中,其到根的路徑長度為i,且其到根的路徑上存在休息點的數量,g[i][1]則表示不存在休息點

f[i][0/1]表示的是當前子樹中的點,其餘定義與g相同

為避免重複計算,計算一顆子樹貢獻時分類討論

ps:根到根這條路徑也記錄在了g陣列內,

所以對於兩端點都不在根上,即根為休息點這種情況

貢獻是:f[0][0]*(g[0][0]-1);

因為長度可能是負數,所以將下標平移??

#include

using

namespace std;

#define ll long long

int n,link[

100010

],d[

100010

],ma;

ll f[

200010][

2],g[200010][

2],ans;

bool vis[

100010];

int sum[

100010

],s,cnt[

200020

],dis[

100010

],min,root,maxx,minn,t=0;

struct dsa

e[200010];

void

insert

(int xx,

int yy,

int zz)

void

get_root

(int now,

int fa)

max=

max(max,s-sum[now]);

if(max}void

get_dis

(int now,

int fa)

cnt[dis[now]

+n]--

;return;}

void

solve

(int now)

}for

(int i=

-ma;i<=ma;i++

) g[i+n][0

]=g[i+n][1

]=0;

for(

int i=link[now]

;i;i=e[i]

.nex)

return;}

intmain()

s=n;

min=

1e9;root=0;

get_root(1

,0);

solve

(root)

;printf

("%lld"

,ans)

;}

bzoj3697 採藥人的路徑 點分治

一道拖了很久的點分治,現在把他搞定了。來自出題人hta的題解 本題可以考慮樹的點分治。問題就變成求過根滿足條件的路徑數。路徑上的休息站一定是在起點到根的路徑上,或者根到終點的路徑上。如何判斷一條從根出發的路徑是否包含休息站?只要在dfs中記錄下這條路徑的和x,同時用個標誌陣列判斷這條路徑是否存在字首...

bzoj3697 採藥人的路徑 (點分治)

原題位址 題意 採藥人的藥田是乙個樹狀結構,每條路徑上種植一種藥,有0 1兩種藥。草藥人希望選擇一條兩種藥材數目相等的路徑,且選出的路徑中有乙個可以作為休息站的節點 不包括起點和終點 滿足起點到休息站和休息站到終點的路徑也是兩種藥數量相等。他一共可以選擇多少種不同的路徑。資料範圍 n 100,000...

BZOJ 3697 採藥人的路徑 點分治

好久不做點分治的題了,正好在聯賽之前抓緊複習一下.先把邊權為 0 的置為 1 定義幾個狀態 f dis 0 1 g dis 0 1 其中 f 代表在當前遍歷的子樹內的答案.其中 f dis 0 表示到根節點距離為 dis 沒有遇到平衡點的個數,f dis 1 表示遇到平衡點的個數.然後就把 f 和 ...