洛谷 P2634 國家集訓隊 聰聰可可

2022-08-04 17:57:19 字數 2422 閱讀 1898

先宣告一下,作者剛學點分治,有講的不好的請指出。

點分治 是一類用來處理樹上路徑的演算法。

點分治,也就是將樹上的點進行分治。點分治的本質就是將一棵樹拆成多棵子樹處理,再不斷往下拆分的過程。

在進行點分治之前,我們必須先找乙個點,我們從這個點進行分治會比較優。那麼這個點怎麼取呢?肯定是比較平衡的點,平衡就意味著這個點的子樹的大小之差盡量小。而這個平衡點就稱為樹的重心。

樹的重心的正式定義:

若存在乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心。(十分顯而易見的就是,我們從這個點向下分治,整棵樹的深度會比較淺,所以時間效率較高)

求重心的方法很簡單,就是乙個 \(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。棋子是沒有區別的 跳動的規則很簡單,任意選一顆棋子,對一顆中軸棋子跳動。跳動後兩顆棋子距離不變。一...