BZOJ3784 樹上路徑

2022-08-20 23:51:19 字數 1621 閱讀 4178

給定乙個\(n\)個結點的樹,結點用正整數\(1..n\)編號。每條邊有乙個正整數權值。用\(d(a,b)\)表示從結點\(a\)到結點\(b\)路邊上經過邊的權值。其中要求\(a < b.\)將這\(n*(n-1)/2\)個距離從大到小排序,輸出前\(m\)個距離值。

統計樹上路徑的問題顯然需要澱粉質(好毒瘤啊,連續考了兩天點分治)。

由於前\(m\)大路徑難以直接統計,而我們又很擅長統計長度大於\(l\)的路徑個數,因此考慮首先二分答案求出第\(m\)大路徑的長度\(l\),再統計長度大於\(l\)的路徑。

分析一波時間複雜度,點分\(o(n\ logn)\),統計路徑時為了方便,我們需要排序後二分(又乙個\(logn\)),本身二分答案就是\(logn\),這樣一來時間複雜度達到了\(o(n\ log^3n)\),難以接受。

考試的時候想到一些小優化,如把點分後的每乙個子樹的根記錄下來。當時也想到了把路徑存下來,但不知道為什麼就認為空間複雜度不正確立馬否定掉了。實際上就是要將路徑存下來,而且空間複雜度為\(o(n\ logn)\)。這樣我們只需要最初建好點分樹併排好序,每次只需要對每乙個點為根的路徑二分一下\(o(n\ logn)\),如此一來演算法的時間複雜度瓶頸為\(o(n\ log^2n)\),本題得到完美解決。

#include using namespace std;

typedef long long ll;

const int maxn=50005;

int n,m,h[maxn],g[maxn];

int rt,root,totsize,size[maxn],mx[maxn];

int lim,path[maxn];ll ans;

vectorv[maxn],g[maxn],ans;

bool vis[maxn];

struct edgee[maxn*2],f[maxn*2];

int getint()

void addedge(int x,int y,int z);h[x]=cnt;

}void addedge(int x,int y);g[x]=cnt;

}void getroot(int x,int fa)

mx[x]=max(mx[x],totsize-size[x]);

if(mx[x]&v)

}void build(int x)

sort(v[x].begin(),v[x].end());

for(int i=h[x];i;i=e[i].next)

}ll calc(vector&v)

}bool judge(int mid)

void dfs2(int x,int fa,int dis)

}void count(int x)

sort(path+now+1,path+path[0]+1);

inplace_merge(path+1,path+now+1,path+path[0]+1); }}

void solve2(int x)

}int main()

memset(vis,0,sizeof(vis));

lim=l;ans=0;solve2(rt);

while(ans.size()());

for(int i=0;i}

bzoj3784 樹上的路徑

time limit 10 sec memory limit 256 mb submit 789 solved 266 submit status discuss 給定乙個n個結點的樹,結點用正整數1.n編號。每條邊有乙個正整數權值。用d a,b 表示從結點a到結點b路邊上經過邊的權值。其中要求a ...

BZOJ3784 樹上的路徑

樹的點分治,在分治的時候將所有點到根的距離依次放入乙個陣列q中。對於一棵子樹裡的點,合法的路徑一定是q l q r 的某個數加上自己到重心的距離。定義五元組 v,l,m,r,w 表示當前路徑長度為v,在 l,r 裡選出最大值m,並加上w。用大根堆維護這些五元組,每次取出v最大的元素,並擴充套件出 l...

BZOJ3784樹上的路徑

題目描述 給定乙個n個結點的樹,結點用正整數1.n編號。每條邊有乙個正整數權值。用d a,b 表示從結點a到結點b路邊上經過邊的權值。其中要求a題解 把每次點分治時的dfs序寫下來,假設我們在乙個位置找能夠和它拼成一條鏈的另乙個位置,可以發現那些位置的順序在dfs序上構成了一段連續區間,用st表 堆...