日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【NOI2013】快餐店【基环树】【树的直径】【set】

發(fā)布時(shí)間:2023/12/3 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【NOI2013】快餐店【基环树】【树的直径】【set】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

傳送門

題意:給一棵nnn個(gè)點(diǎn)的基環(huán)樹,找一個(gè)點(diǎn)(可以在邊上),求所有節(jié)點(diǎn)到這個(gè)點(diǎn)的最大值的最小值。

n≤1e5n \leq1e5n1e5

先考慮一棵普通樹的情況

顯然是直徑長(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)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。