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...