邊分治+邊分樹合併
這個題很多做法都是啟發式合併的複雜度的,都有點卡
以前有個套路叫做線段樹合併優化啟發式合併,消掉乙個 \(log\)
這個題思路類似,建出邊分樹,通過一些操作把它變成線段樹,就可以線段樹合併了
首先邊分樹的相關定理:
如果一棵包含 \(n\) 個結點的樹中每個點的度均不大於 \(d\),那麼存在一條邊,使得分出的兩棵子樹的結點個數在 \([n/(d+1),n*d/(d+1)]\)
那麼邊分樹的深度和度數是相關的,我們只需要通過加虛點把這棵樹變成二叉樹就好了
回到這個題:
列舉第二棵樹的 \(lca\) , 然後剩下的就是在第二棵樹中選出在第一棵樹中 \(dep[x]+dep[y]-dep[lca(x,y)]\) 的最大值
我們發現這個要求的東西就是 \(x,y\) 到根的路徑的交,所以可以不考慮第一棵樹的 \(lca\) 了
其中 \(x,y\) 都來自這個 \(lca\) 的不同子樹內
每次插入乙個點就像線段樹那樣更新就行了,不同的是你不能準確定位到這個葉子節點,你需要在 \(build\) 的時候順便存一下對應關係
列舉第二棵樹的 \(lca\) 再合併子樹的邊分樹,順便更新一下答案就行了
#include#define vc vector::iterator
#define pb push_back
using namespace std;
typedef long long ll;
const int n=750000,m=8510000,t=n*2;
int n,v,sz[n],sum,son[n]=,val[t],ls[t],rs[t],dep[n],fa[t],tt=0;
ll f[n][20],dis[n],fl[m],fr[m],ans=0,d;int lm[m],rm[m],rt[n/2],id[m];
struct edge
edge(int _x,int _v)
}q[n];
vectorg1[n],g2[n/2];
inline void add(int x,int y,int z,vector*g)
inline void build(int x,int last)
int l=1,r=0;edge u,v;
for(vc it=g1[x].begin();it!=g1[x].end();++it)if(it->x!=last)q[++r]=*it;
while(l+2<=r)
vector().swap(g1[x]);
while(l<=r)add(x,q[l].x,q[l].v,g1),l++;
}inline void getdis(int x,int last,int d)
}inline void getedge(int x,int last,int &ex,int &ey)
for(vc it=g1[ey].begin();it!=g1[ey].end();++it)
if(it->x==ex)
fa[ls[o]=solve(ex,s-sz[ey],d+1)]=o;
fa[rs[o]=solve(ey,sz[ey],d+1)]=o;
return o;
}inline int ins(int x)
return tt;
}inline int merge(int x,int y)
inline void dfs(int x,int last,ll d)
}int main()
BZOJ 1919 Ctsc2010 效能優化
題目 題意 給出兩個長度為 n 的整數序列a 0.n 1 b 0.n 1 和非負整數 c 對於兩個長度為 n的整數序列,定義 運算,結果為乙個長度為 n的整數序列,例如f g h 則有h k i j k modn f i g j 求a b b b 每一位模 n 1 的值,其中有 c 個 運算,n 1...
bzoj 2306 Ctsc2011 幸福路徑
有向圖 g有n個頂點 1,2,n,點i 的權值為 w i 現在有乙隻螞蟻,從 給定的起點 v0出發,沿著圖 g 的邊爬行。開始時,它的體力為 1。每爬過一條邊,它的體力都 p,而螞蟻爬到某個頂點時的幸福度,是它當時的體力與該點權值的乘積。求最大幸福值。因為當體力很小後,對答案就沒什麼影響力,所以用乙...
BZOJ 5343 Ctsc2018 混合果汁
bzoj 5343 ctsc2018 混合果汁 二分答案 主席樹 題意 給出每個果汁的 p,美味度d,最多能放的體積l。定義果汁混合後的美味度為果汁的美味度的最小值。m次詢問,要求花費不大於g,總體積不小於l,求最大美味度,如果不能滿足,輸出 1。二分答案。然後轉變為求 前l小的果汁之和。類似任務查...