給定一棵\(n\)個結點的樹,結點用正整數\(1 \dots n\)編號,每條邊有乙個正整數權值。用\(d(a, b)\)表示從結點\(a\)到結點\(b\)路徑上經過邊的權值和,其中要求\(a < b\)。將這\(\frac\)個距離值從大到小排序,輸出前\(m\)個距離值。
第一行包含兩個正整數\(n,m\)。下面\(n − 1\)行,每行三個正整數\(a, b, c (a, b \le n, c \le 10,000)\),表示結點\(a\)和結點\(b\)間有一條權值為\(c\)的邊相連。
共\(m\)行,每行乙個正整數,第\(i\)行表示排在第\(i\)個的距離值。
5 101 2 1
1 3 2
2 4 3
2 5 4
7765443
321
\(n \le 50000,m \le min(\frac,30,000)\)點分治+k路歸併。由於樹上的每條路徑必定經過乙個重心,在進行點分治時我們可以列舉到所有的路徑。將重心到每個點的距離按dfs序插入陣列(可以把每次分治的結果都插入陣列中,陣列開\(o(nlogn)\))中。由於保證列舉的兩個點不在一棵子數中,每個點對應的鏈在dfs陣列中一定是段連續的區間,故可以採用超級鋼琴的做法。**如下:
#include#include#include#include#include#include#includeusing namespace std;
#define maxn (100010)
int n,m,next[maxn],toit[maxn],len[maxn],side[maxn],l,r,f[20][maxn*10],bit[maxn*10];
int cnt = 1,num,size[maxn],large[maxn],dis[maxn*10],best; bool vis[maxn];
struct node
};vector vec; multiset s;
inline void add(int a,int b,int c)
inline void ins(int a,int b,int c)
inline void getroot(int now,int fa,int rest)
large[now] = max(large[now],rest-size[now]);
if (large[now] < large[best]) best = now;
}inline int find_root(int now,int rest)
inline void dfs(int now,int fa,int d)
); for (int i = side[now];i;i = next[i])
if (toit[i] != fa&&!vis[toit[i]])
dfs(toit[i],now,d+len[i]);
}inline void cut(int now)
for (int i = side[now];i;i = next[i])
if (!vis[toit[i]]) cut(find_root(toit[i],size[toit[i]]));
}inline int query(int l,int r)
int nn = vec.size();
for (int i = 0;i < nn;++i)
for (int i = 1;i <= m;++i)
if (now.mx < now.r)
}fclose(stdin); fclose(stdout);
return 0;
}
1490 樹上的路徑
題意 記憶體限制 256 mib 時間限制 1000 ms 給定一棵 n nn 個結點的樹,結點用正整數 1 n 1 n1 n 編號,每條邊有乙個正整數權值。用 d a b d a,b d a,b 表示從結點 a aa 到結點 b bb 路徑上經過邊的權值和,其中要求 a a b 將這 n n 1 ...
1490 樹上的路徑
題意 記憶體限制 256 mib 時間限制 1000 ms 給定一棵 n 個結點的樹,結點用正整數 1 n 編號,每條邊有乙個正整數權值。用 d a,b 表示從結點 a 到結點 b 路徑上經過邊的權值和,其中要求 a n leq 50000 m leq min frac,300000 題解 考慮點分...
樹上的好題
給出乙個n個節點的有根樹 編號為0到n 1,根節點為0 乙個點的深度定義為這個節點到根的距離 1。設dep i 表示點i的深度,lca i,j 表示i與j的最近公共祖先。有q次詢問,每次詢問給出l r z,求sigma dep lca i,z 即,求在 l,r 區間內的每個節點i與z的最近公共祖先的...