【NOI2013】快餐店【基环树】【树的直径】【set】
生活随笔
收集整理的這篇文章主要介紹了
【NOI2013】快餐店【基环树】【树的直径】【set】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
題意:給一棵nnn個點的基環樹,找一個點(可以在邊上),求所有節點到這個點的最大值的最小值。
n≤1e5n \leq1e5n≤1e5
先考慮一棵普通樹的情況
顯然是直徑長度的一半
因為如果有個點大于直徑長度的一半,顯然可以找一個更長的鏈,所以這個長度可以覆蓋所有點。而如果小于,不能覆蓋直徑的端點。
如果是基環樹,發現仍然可以按普通樹的形式覆蓋所有點。也就是斷掉環上的一條邊后的最小直徑。
非環邊是不受影響的,分別跑一次直徑記錄下來。
對每個環上的點記錄最大深度,套路性地斷環為鏈,set瞎搞一下就出來了
和前面的最大直徑取max輸出
復雜度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; }總結
以上是生活随笔為你收集整理的【NOI2013】快餐店【基环树】【树的直径】【set】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【NOI2013】树的计数【树的遍历】【
- 下一篇: 误杀有彩蛋吗 电影误杀的片尾彩蛋有没惊喜