記得是9月月賽題,當時做的時候覺得跟zjoi2015幻想鄉戰略遊戲那道題很像???,就寫了,然後就寫掛了。。。
我們發現假設當前點為根,我們算出\(m\)次詢問中最遠的\(a\)對點,如果這\(a\)對點,全部都兩個點在根的不同子樹中。當前點就是最優的就是答案。當全部\(a\)對點都在乙個子樹中,我們把答案改為那個子樹對應的兒子,答案會變優。當有幾對點在乙個子樹,另外幾對點在另外的子樹中,當前答案還是最優的。
所以本題的乙個想法就是,乙個乙個的改變根使答案變優。
但是上述想法要求我們每一次移動乙個點都要遍歷整棵樹。是在太慢了。
我們考慮用點分治的方法優化演算法。當全部\(a\)對點都在乙個子樹中時,乙個更優的答案在那個子樹中,我們找到這個子樹的重心當作根。這樣最多遍歷\(logn\)次。把複雜度變為了\(o(mlogn)\)。至此本題得到完美解決。
#include#include#include#include#includeusing namespace std;
const int n=101000;
int cnt,head[n];
int g[n],size[n],all,root,dis[n],ans1[n],ans2[n],dep[n],fa[n][25],vis[n];
int n,m,a[n],b[n],ans;
struct edgee[n*2];
void add_edge(int u,int v,int w)
int read()
while(ch>='0'&&ch<='9')
return sum*f;
}void getroot(int u,int f)
g[u]=max(g[u],all-g[u]);
if(g[u]=0;i--)
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}int up(int u,int x)
} ans=min(ans,tmp);
tmp=0;
for(int i=1;i<=cnt;i++)
} if(tmp==-1)return -1;
return tmp;
}void work(int u) }}
int main()
for(int i=1;i<=m;i++)a[i]=read(),b[i]=read();
ans=1e9;
g[0]=n+10,all=n;
getroot(1,0);work(root);
printf("%d",ans);
return 0;
}
洛谷4886 快遞員 點分治
題目鏈結 題意 給你一棵n個點的樹,有m個點對,你要在樹上找乙個點x,使得對於所有的點對 u,v dis x,u dis x,v 最小,輸出這個最小值。n,m 100000 題解 感覺之前點分治學得不好,所以最近想補一下。這個題其實拿到題想過點分治,但是好像並不滿足分治常見的子問題結構,就沒想好怎麼...
遞迴 重心 Luogu P4886 快遞員
bob 的城市裡有 nn 個郵遞站,由於經濟考慮,這些郵遞站被 n 1n 1 條帶權無向邊相連。即 這 nn 個郵遞站構成了一棵樹。bob 正在應聘乙個快遞員的工作,他需要送 mm 個商品,第 ii 個商品需要從 uu 送到 vv。由於 bob 不能帶著商品走太長的路,所以對於一次送貨,他需要先從快...
題解 洛谷 P4886 快遞員
考慮乙個節點成為根節點後,如何判斷其為最優的。若最長距離的路徑中的任意一條滿足兩個端點在當前根節點的兩個不同的兒子中,則當前根節點為最優的。因為若將其調整為不在該路徑上的點,最長路徑的值會變大,將其調整為該路徑上別的點,可能會產生更長的路徑,因此該根節點為最優的。若存在兩條最長距離的路徑的端點不來自...