bzoj3784 樹上的路徑

2021-08-09 11:33:51 字數 1853 閱讀 6598

time limit: 10 sec  

memory limit: 256 mb

submit: 789  

solved: 266 [

submit][

status][

discuss]

給定乙個n個結點的樹,結點用正整數1..n編號。每條邊有乙個正整數權值。用d(a,b)表示從結點a到結點b路邊上經過邊的權值。其中要求a

第一行兩個正整數n,m

下面n-1行,每行三個正整數a,b,c(a,b<=n,c<=10000)。表示結點a到結點b有一條權值為c的邊。

共m行,如題所述.

5 10

1 2 1

1 3 2

2 4 3

2 5 4 77

6 5

4 4

3 3

2 1

n<=50000,m<=min(300000,n*(n-1) /2 ) [

submit][

status][

discuss]

先把樹轉換成點分治序列,然後做法同noi2010超級鋼琴

**:

#include#include#include#include#include#includeusing namespace std;

const int maxn = 50100;

struct edge;

int s[maxn * 20];

struct data

};int n,m;

int maxid[20 * maxn][20],length[20 * maxn];

priority_queueq;

vectore[maxn];

bool vis[maxn];

int siz[maxn],weight[maxn],id,dfn[maxn],pos[20 * maxn],cmax[20 * maxn],tot;

inline int getint()

inline void dfs_siz(int u,int fa,int t)

siz[u]++;

weight[u] = max(weight[u],t - siz[u]);

if (weight[u] < weight[id]) id = u;

}inline void cal(int u,int fa)

}inline void st_init()

for (int i = 1; i <= tot; i++) maxid[i][0] = i;

for (int j = 1; j <= 20; j++)

for (int i = 1; i <= tot; i++) }

inline int query_maxid(int l,int r)

inline void solve(int u)

cmax[dfn[u]] = dfn[u];

for (int i = dfn[u] + 1; i <= tot; i++)

); }

vis[u] = 1;

for (int i = 0; i < e[u].size(); i++) }

int main()

); e[v].push_back((edge));

} dfs_siz(1,0,0);

weight[0] = 2147483647;

solve(1);

st_init();

for (int i = 1; i <= m; i++)

); if (nl <= r) q.push((data));

} return 0;

}

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

BZOJ3784 樹上的路徑

思路1 澱粉質。用priority queue維護前 m 長的路徑的長度。用multiset維護點分治時,之前所有子樹的路徑長度,然後對於新子樹中的每一條路徑,在multiset中從大往小列舉另一半路徑拼一起並嘗試加入優先佇列。如果加入失敗,那麼對於這個點,集合中再往前的數也不會成功,可以直接跳掉。...