【NOI2013】快餐店【基环树】【树的直径】【set】
生活随笔
收集整理的這篇文章主要介紹了
【NOI2013】快餐店【基环树】【树的直径】【set】
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
傳送門
題意:給一棵nnn個(gè)點(diǎn)的基環(huán)樹,找一個(gè)點(diǎn)(可以在邊上),求所有節(jié)點(diǎn)到這個(gè)點(diǎn)的最大值的最小值。
n≤1e5n \leq1e5n≤1e5
先考慮一棵普通樹的情況
顯然是直徑長(zhǎng)度的一半
因?yàn)槿绻袀€(gè)點(diǎn)大于直徑長(zhǎng)度的一半,顯然可以找一個(gè)更長(zhǎng)的鏈,所以這個(gè)長(zhǎng)度可以覆蓋所有點(diǎn)。而如果小于,不能覆蓋直徑的端點(diǎn)。
如果是基環(huán)樹,發(fā)現(xiàn)仍然可以按普通樹的形式覆蓋所有點(diǎn)。也就是斷掉環(huán)上的一條邊后的最小直徑。
非環(huán)邊是不受影響的,分別跑一次直徑記錄下來(lái)。
對(duì)每個(gè)環(huán)上的點(diǎn)記錄最大深度,套路性地?cái)喹h(huán)為鏈,set瞎搞一下就出來(lái)了
和前面的最大直徑取max輸出
復(fù)雜度O(nlogn)O(nlogn)O(nlogn)
#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <utility> #include <set> #define MAXN 100005 #define MAXM 200005 using namespace std; typedef long long ll; inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } struct edge{int u,v,w;}e[MAXM]; int head[MAXN],nxt[MAXM],cnt; void addnode(int u,int v,int w) {e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt; } bool vis[MAXN],isrt[MAXN]; int lop[MAXN],x[MAXN],tot,tmp; ll dep[MAXM]; void dfs(int u,int f) {vis[u]=true;for (int i=head[u];i;i=nxt[i])if (!vis[e[i].v]&&e[i].v!=lop[1]){dfs(e[i].v,u);if (isrt[e[i].v]&&e[i].v!=tmp) isrt[lop[++tot]=u]=true,x[tot]=e[i].w;}elseif (e[i].v!=f&&e[i].v!=lop[1])isrt[lop[++tot]=u]=true,x[tot]=e[i].w,tmp=e[i].v;vis[u]=false; } ll dis[MAXN]={-1}; int mx; void getdis(int u,int f) {if (dis[u]>dis[mx]) mx=u;for (int i=head[u];i;i=nxt[i])if (e[i].v!=f&&!isrt[e[i].v]){dis[e[i].v]=dis[u]+e[i].w;getdis(e[i].v,u);} } typedef pair<ll,int> pi; multiset<pi> s1,s2;//+,- inline ll calc(){return s1.rbegin()->second==s2.rbegin()->second? max((++s1.rbegin())->first+s2.rbegin()->first,s1.rbegin()->first+(++s2.rbegin())->first):s1.rbegin()->first+s2.rbegin()->first;} ll sum[MAXM]; int main() {int n=read();for (int i=1;i<=n;i++){int u,v,w;u=read(),v=read(),w=read();addnode(u,v,w);addnode(v,u,w);}dfs(1,0);ll ans0=0;for (int i=1;i<=tot;i++){isrt[lop[i]]=false;mx=0;dis[lop[i]]=mx=0;getdis(lop[i],0);dep[i]=dis[mx];dis[mx]=0;getdis(mx,0);ans0=max(ans0,dis[mx]);isrt[lop[i]]=true;}for (int i=2;i<=tot;i++) sum[i]=sum[i-1]+x[i];for (int i=tot+1;i<=2*tot;i++) sum[i]=sum[i-1]+x[i-tot],dep[i]=dep[i-tot];ll ans1=1e18;for (int i=1;i<=tot;i++) s1.insert(make_pair(dep[i]+sum[i],i)),s2.insert(make_pair(dep[i]-sum[i],i));ans1=min(ans1,calc());for (int i=tot+1;i<=2*tot-1;i++){s1.erase(s1.find(make_pair(dep[i-tot]+sum[i-tot],i-tot)));s2.erase(s2.find(make_pair(dep[i-tot]-sum[i-tot],i-tot)));s1.insert(make_pair(dep[i]+sum[i],i));s2.insert(make_pair(dep[i]-sum[i],i));ans1=min(ans1,calc());}ans1=max(ans0,ans1);printf("%lld.%d\n",ans1>>1,(ans1&1)? 5:0);return 0; }總結(jié)
以上是生活随笔為你收集整理的【NOI2013】快餐店【基环树】【树的直径】【set】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【NOI2013】树的计数【树的遍历】【
- 下一篇: 【NOI2016】循环之美【莫比乌斯反演