先宣告一下,作者剛學點分治,有講的不好的請指出。
點分治 是一類用來處理樹上路徑的演算法。
點分治,也就是將樹上的點進行分治。點分治的本質就是將一棵樹拆成多棵子樹處理,再不斷往下拆分的過程。
在進行點分治之前,我們必須先找乙個點,我們從這個點進行分治會比較優。那麼這個點怎麼取呢?肯定是比較平衡的點,平衡就意味著這個點的子樹的大小之差盡量小。而這個平衡點就稱為樹的重心。
樹的重心的正式定義:
若存在乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心。(十分顯而易見的就是,我們從這個點向下分治,整棵樹的深度會比較淺,所以時間效率較高)
求重心的方法很簡單,就是乙個 \(dfs\)。
void getroot(int x,int father)
getroot(to,x);
f[x]=max(f[x],size[to]);//因為我們若以點x為根,則還有一棵子樹,就是x和上面深度小於x的所有點
size[x]+=size[to];
} f[x]=max(f[x],sum-size[x]);
if(f[x]分治的實現:
實現分治我們要先進行求深度的預處理,就是下面的\(getdep\)函式,\(getdepth\)也就是求以\(x\)為某個點為根,則其下面的點到根的距離。
void getdepth(int x,int father)
d[to]=d[x]+e[i].val;
getdepth(to,x);
}}
然後就是我們的\(solve\)函式,\(solve\)函式也是一步步分治。
下面是solve的通式,其中cal是計算值的函式,\(cal\)的第二個引數表示該點到當前重心的距離,我們剛開始先加上 \(cal\)
\((x,0)\)。即為將下面的所有狀況都加起來。但有一些狀況是不合法的,所以我麼要減掉,也就減掉\(cal\)
\((son[j],w[j])\)的情況。因為我們想要處理的是經過\(x\)的情況,而有可能在\(x\)子樹中的兩點滿足情況,但它們的\(lca\)不為\(x\),也就是不經過\(x\)。那麼這種情況在\(x\)時是不合法的,但是我們加進去了,所以我們再減去\(cal\)
\((son[j],w[j])\)即可。
void solve(int x)
dep[0]=0;
d[to]=e[i].val;
getdepth(to,x);
for(int j=1;j<=dep[0];j++)
for(int j=1;j<=dep[0];j++)
} for(int i=1;i<=top;i++)
for(int i=head[x];~i;i=e[i].nxt)
root=0;
sum=size[to];
getroot(to,x);
solve(root);
}}
在時間充裕的時候,我們可以開乙個佇列,然後將x不同子樹裡的點進行配對(這樣可以避免不合法的情況)。
想知道更多知識點這
這題十分明顯是可以點分治的。
我們要求的就是所有樹上路徑為 \(3\) 的倍數的條數,首先每個點單獨成為路徑,則長度為\(0\),肯定滿足條件,所以\(ans\)
\(=\)
\(n\)。然後我們就進行點分治,在點分治的時候我們就可以不用上文的\(solve了\),因為只有三種情況,\(x≡0(mod 3)\),\(x≡1(mod 3)\),\(x≡2(mod 3)\),所以我們直接開乙個大小為\(3\)的陣列,將路徑到\(x\)的距離按照被\(3\)模分類,最後累加即可。
可愛的小**:
#include#include#includeusing namespace std;
typedef long long int ll;
const ll max_n=20010;
struct edgee[max_n<<1];
ll n,head[max_n<<1],cnt,f[max_n],ans,sum,root,size[max_n],vis[max_n],flag[4],d[max_n],dep[max_n],son[max_n],que[max_n],top;
inline ll read()
c=getchar();
} while(c>='0'&&c<='9')
return x*f;
}void init()
void add(int x,int y,int w)
void getroot(int x,int father)
getroot(to,x);
f[x]=max(f[x],size[to]);
size[x]+=size[to];
} f[x]=max(f[x],sum-size[x]);
if(f[x]希望luogu能通過我的題解qaq
洛谷 P2634 國家集訓隊 聰聰可可
先宣告一下,作者剛學點分治,有講的不好的請指出。點分治 是一類用來處理樹上路徑的演算法。點分治,也就是將樹上的點進行分治。點分治的本質就是將一棵樹拆成多棵子樹處理,再不斷往下拆分的過程。在進行點分治之前,我們必須先找乙個點,我們從這個點進行分治會比較優。那麼這個點怎麼取呢?肯定是比較平衡的點,平衡就...
洛谷 P1505 國家集訓隊 旅遊
洛谷傳送門 ray 樂忠於旅遊,這次他來到了 t 城。t 城是乙個水上城市,一共有 nn 個景點,有些景點之間會用一座橋連線。為了方便遊客到達每個景點但又為了節約成本,t 城的任意兩個景點之間有且只有一條路徑。換句話說,t 城中只有 n 1n 1 座橋。ray 發現,有些橋上可以看到美麗的景色,讓人...
洛谷 P1852 國家集訓隊 跳跳棋
跳跳棋是在一條數軸上進行的。棋子只能擺在整點上。每個點不能擺超過乙個棋子。我們用跳跳棋來做乙個簡單的遊戲 棋盤上有3顆棋子,分別在a,b,c這三個位置。我們要通過最少的跳動把他們的位置移動成x,y,z。棋子是沒有區別的 跳動的規則很簡單,任意選一顆棋子,對一顆中軸棋子跳動。跳動後兩顆棋子距離不變。一...