bzoj 1468 Tree 點分治模板

2022-04-06 03:52:12 字數 2851 閱讀 1458

time limit: 10 sec  memory limit: 64 mb

submit: 1527  solved: 818

[submit][status][discuss]

給你一棵tree,以及這棵樹上邊的距離.問有多少對點它們兩者間的距離小於等於k

n(n<=40000) 接下來n-1行邊描述管道,按照題目中寫的輸入 接下來是k

一行,有多少對點之間的距離小於等於k

71 6 13

6 3 9

3 5 7

4 1 3

2 4 20

4 7 2 105

/*

思路:最容易想到的演算法是:從每個點出發遍歷整棵樹,統計數對個數。

由於時間複雜度o(n^2),明顯是無法滿足要求的。

對於一棵有根樹, 樹中滿足要求的乙個數對所對應的一條路徑,必然是以下兩種情況之一:

1、經過根節點

2、不經過根節點,也就是說在根節點的一棵子樹中

對於情況2,可以遞迴求解,下面主要來考慮情況1。

設點i的深度為depth[i],父親為parent[i]。

若i為根,則belong[i]=-1,若parent[i]為根,則belong[i]=i,否則belong[i]=belong[parent[i]]。

這三個量都可以通過一次bfs求得。

我們的目標是要統計:有多少對(i,j)滿足ibelong[j]

如果這樣考慮問題會變得比較麻煩,我們可以考慮換一種角度:

設x為滿足ii,那麼i對答案的貢獻為b[i]-i。

綜上,設遞迴最大層數為l,因為每一層的時間複雜度均為「瓶頸」——排序的時間複雜度o(nlogn),所以總的時間複雜度為o(l*nlogn)

然而,如果遇到極端情況——這棵樹是一根鏈,那麼隨意分割勢必會導致層數達到o(n)級別,對於n=10000的資料是無法承受的。因此,我們在每一棵子樹中選擇「最優」的點分割。所謂「最優」,是指刪除這個點後最大的子樹盡量小。這個點可以通過樹形dp在o(n)時間內求出,不會增加時間複雜度。這樣一來,即使是遇到一根鏈的情況時,l的值也僅僅是o(logn)的。

因此,改進後演算法時間複雜度為o(nlog^2n),可以ac。

/*

學習 思路

#include#include

#include

#include

#define inf 0x3f3f3f3f

#define maxn 40010

using

namespace

std;

struct

node

e[maxn

<<1

];int

head[maxn],vis[maxn],son[maxn],deep[maxn],f[maxn],d[maxn];

intn,cnt,root,sum,k,ans,num,x,y,z,l;

inline

intread()

while(c>='

0'&&c<='9')

return x*f;

}inline

void add(int u,int v,int

dis)

inline

void

init()

}void get_root(int now,int

fa) f[now]=max(f[now],sum-son[now]);

if(f[now]now;

}void get_deep(int now,int

fa)}

int cal(int now,int

dis)

returnt;}

void work(intu)}

intmain()

**

#include#include

#define n 40005

using

namespace

std;

struct arra[n*2

];int

end[n],son[n],f[n],d[n],data[n];

intcnt,l,all,ans,i,x,y,z,n,root,k;

bool

can[n];

void add(int u,int v,int

s)void get_root(int k,int

fa)

if (all-son[k]>f[k]) f[k]=all-son[k];

if (f[k]k;

}void get_array(int k,int

fa)}

int calc(int k,int

now)

void work(intk)}

intmain()

標程

#include using

namespace

std;

#define paichucuowucaibreak true

intmain()

}return0;

}

對拍

#include using

namespace

std;

#define maxn 10004

#define justval 68451

#define justval_ 15641684

intl[maxn],r[maxn],n,lo,ro;

intmain()

printf(

"%d\n

",rand()%justval_);

return0;

}

資料生成 一棵樹

BZOJ1468 Tree 點分治入門練習題

點分治見bzoj2152 此題只是同時需要把點到根的距離存到陣列裡,可以用sort排序然後再統計 arr陣列排序後只要arr l arr r 小於k,則arr l 與arr中下標 l 1,r 任意乙個的和都滿足要求,直接統計 include include include includeusing ...

1468 Tree 樹的點分治

樓教主男人八題之一 好可怕 似乎不是很難的樣子。點分治大致是這樣 先選出乙個根 一般是重心 然後可以把兩個點之間的路徑分為經過根的和不經過根的,經過根的直接處理記錄,不經過根的遞迴處理計算。似乎還用到了容斥原理的方法。記錄經過當前根的方案數的方法是 先以當前的根為起點遍歷一遍記下di s 陣列即到根...

Tree(樹分治 點分治)

原題 poj 1741 題意 有一棵n個節點的樹,每條邊都有乙個權值,問有多少個節點之間的距離小於等於k,解析 典型的樹分治,對於每一棵樹,我們首先找到它的重心 重心 一棵樹中以這個點為root時的最大子樹的節點數最小 int siz n maxn n 這棵子樹大小,最大子樹大小 void getg...