思路1:
澱粉質。用priority_queue
維護前\(m\)長的路徑的長度。用multiset
維護點分治時,之前所有子樹的路徑長度,然後對於新子樹中的每一條路徑,在multiset
中從大往小列舉另一半路徑拼一起並嘗試加入優先佇列。如果加入失敗,那麼對於這個點,集合中再往前的數也不會成功,可以直接跳掉。
這種方法非常顯然,但會被長度遞增的路徑序列卡掉。
**:
#includeusing namespace std;
int n,m,head[50100],cnt,sz[50100],msz[50100],root,sz;
priority_queue,greater>q;
bool vis[50100];
multisets;
vectorv;
struct nodeedge[100100];
void ae(int u,int v,int w)
void getroot(int x,int fa)
思路2:
有一種東西叫做「澱粉徐點分序」,即澱粉質過程中所有訪問過的節點所組成的序列,即所有分治樹的dfs序的拼接。顯然,它的長度是\(o(n\log n)\)的(即澱粉質常規複雜度)。那麼它有什麼用呢?
我們考慮單次分治的分治樹。則對於乙個節點來說,一條經過分治樹根的路徑的另一端,必定存在於分治樹中除了它所在的那顆子樹外其他的位置。因為整棵分治樹在澱粉質時是一段連續的序列,而它所在的子樹也是一段連續序列(dfs序的性質),所以節點\(x\)的路徑另一端所在位置可以這麼表示:\((x,l,r)\),即一端是點分序中的第\(x\)個位置,另一端可以在點分序中區間\([l,r]\)內的任何位置。這就是[noi2010]超級鋼琴的內容。直接用堆+st表即可在\(o(n\log n)\)時間內完成。詳情可見該題題解,不再贅述。因為總序列長度是\(o(n\log n)\)的,因此總複雜度是\(o(n\log^2n)\)。
**:
#includeusing namespace std;
int n,m,head[50100],cnt,sz[50100],msz[50100],root,sz,dfn[1001000],mx[1001000][20],tot,lg[1001000];
int max(int x,int y)
int calc(int l,int r)
int r=tot;
for(int j=0;jx=v[j];
for(int i=x.first+1;i<=x.second-1;i++)vv.push_back(node(i,l,x.first)); }}
void solve(int x)
}int main()
return 0;
}
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表 堆...