這篇不算題解,是讓自己複習的,什麼都沒說清楚。
很久沒有寫點分治了,以前為了趕課件學的太急,板子都沒打對就照著題解寫題,導致學得很不紮實。
這道題差不多是在郭老師的指導下一點點湊出來的,還是沒能自己完整寫出一道題,慚愧。
這道題大意是:給出一棵邊權為0/1的樹,求滿足以下條件的路徑總數:0的個數等於1的個數,且路徑上存在一點到路徑兩端也滿足該條件。
這種求路徑總數的題,可以想到用點分治。
把0看作-1,就可以轉化為路徑邊權和為0。
如果沒有休息點這個條件是很容易統計的,加上這個條件我們就要多記一些資訊了。
點分治的容斥寫法應用範圍有限,用另一種寫法會更方便。
類似樹形揹包,我們在統計經過u點的路徑條數時,維護了乙個之前遍歷過的子樹上的路徑集合,每次進入一棵新子樹,記錄一下現在走的鏈,和之前集合裡的鏈拼在一起形成答案,最後把現在的鏈加入集合中。
所以對這道題,我們維護現在走的路徑和之前的路徑集合時都分作兩類:有休息點和沒有休息點。
現在有休息點的路徑某段字尾和為0,有一段和為0等價於有兩點字首和相等,開桶記錄字首和,類似p3941 入陣曲那道題。
沒有休息點的路徑用路徑集合中有休息點的路徑匹配,有休息點的路徑之前有沒有休息點都能匹配。
現在走的有休息點的路徑可能本身已經滿足條件了,要記入答案。
注意:休息點也可以不在路徑上某點,而在根節點,即兩邊各有一條「1、-1」的路徑,要加上這種情況。
#include using namespace std;
const int n=3e5+5,inf=0x3f3f3f3f;
int n,rt,rtsiz,tot[2],d[2][n],siz[n];
long long ans;
bool del[n];
struct bucket
inline int ask(int pos)
}cnt[2],vis;
int top,ver[n],val[n],nxt[n],head[n];
inline void add(int x,int y,int z)
void findrt(int u,int fa,int all)
mxsiz=max(mxsiz,all-siz[u]);
if(mxsiz}void getdis(int u,int fa,int dis)
if(!op) vis.add(dis,-1);//如果是第一次出現 就退棧 倒出桶
}void calc(int u) }}
void dfs(int u)
}int main()
rtsiz=inf;
findrt(1,0,n);
dfs(rt);
printf("%lld\n",ans);
return 0;
}
FJ2014集訓 採藥人的路徑
啦啦啦 來寫一篇題解 統計路徑?嗯往點分治上想。把0和1轉化為 1和1,求和完dis為0的路徑就是陰陽平衡的路徑了。如果題目沒有限制要有中間休息站那就是比較裸的點分治澱粉質題了。用兩個陣列 f dis 和g dis f dis 此時dfs的這棵子樹裡到根距離為dis的路徑條數。g dis 此時dfs...
bzoj3697 FJ2014集訓 採藥人的路徑
小道士的矯情之路 點分治,對於每個子樹,處理其內經過根 重心 的路徑,然後遞迴下一層子樹 如何處理經過根的合法路徑 合法有兩個要求 把輸入的0改成 1後 1.len 0 2.存在乙個點i使被她分開的兩個路徑len均為零 在每次統計中我們可以dfs統計每條從根開始的路徑 half way 任意兩條這樣...
P4841 集訓隊作業2013 城市規劃
設 f i 表示 i 個點的無向連通圖個數,g i 表示 i 個點的無向圖個數。列舉 1 所在連通塊的大小,有 g i sum limits ic f jg 化簡得 g i sum limits i fracf jg frac sum limits i frac frac 設 f i frac,g ...