bzoj3697 採藥人的路徑 點分治

2022-05-01 23:06:18 字數 1587 閱讀 1616

採藥人的路徑 bzoj-3697

題目大意:給你乙個n個節點的樹,每條邊分為陰性和陽性,求滿足條件的鏈的個數,使得這條鏈上陰性的邊的條數等於陽性的邊的條數,且這條鏈上存在乙個節點,這個節點到乙個端點的鏈也是陰陽相等,到另乙個頂點也是陰陽相等。

注釋:$1\le n \le 10^5$。

想法:點分治裸題,開始淨想著怎麼在一條陰陽相等的鏈上找點了。其實可以在找初步滿足條件的鏈是就直接處理出完全滿足條件者。首先,我們先令陽性為1,陰性為-1,求邊權和為0即為陰陽相等。緊接著,我們定義

f[i][1]表示root的子樹中滿足到重心的鏈且邊權和為i、存在乙個點使得該點到這條鏈上到不是重心的另乙個節點的邊權和為0的條數。

f[i][0]同理,只是不存在這樣的點。

g[i][1/0]表示邊權和為-i。

特別地,因為所有的邊權都是1 or -1,所以我可以在dfs鏈的時候直接判斷出是否存在這樣的節點。具體地:這條鏈的邊權是x,如果這個節點相對於重心是根節點來講存在乙個祖先,使得這個祖先到根節點的邊權和也是x,那麼顯然就存在這樣的節點,就是那個祖先。然後,我們可以用l和r分別表示這個點之前祖先的邊權和所能達到的下界和上界。因為邊權是1 or -1,所以$[l,r]$之間的所有值都是可以取到的。這就處理出了f和g陣列。

剩下的,就是運用單步容斥和簡單的點分治模板套用,注意size的問題(抄的gxzlegend的**,所以就沒特意更改size的錯誤)。

最後,附上醜陋的**... ...

#include #include #include #include using namespace std;

int main()

#include #include #include #define n 100010

using namespace std;

int head[n],to[n<<1],val[n<<1],next[n<<1],cnt,vis[n],si[n],ms[n],sum,root,md;

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

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

void getroot(int x,int fa)

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

if(!vis[to[i]]&&to[i]!=fa)

calc(to[i],x,now+2*val[i]-1,cnt);

}void dfs(int x,int fa,int now,int l,int r)

else

l=min(l,now),r=max(r,now),md=max(md,max(-l,r));

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

if(!vis[to[i]]&&to[i]!=fa)

dfs(to[i],x,now+val[i]*2-1,l,r);

}void solve(int x) }}

int main()

{ int n,x,y,z;

scanf("%d",&n);

for(int i=1;i小結:在更新l和r時now的值並沒有進行更改,所以不需要特殊處理,也就是當前的calc的now是可以直接拿來用的。

BZOJ3697 採藥人的路徑

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

bzoj3697 採藥人的路徑

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

bzoj3697 採藥人的路徑

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