[bzoj1791][ioi2008]Island 岛屿(基环树树的直径)
Posted rikurika
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj1791][ioi2008]Island 岛屿(基环树树的直径)相关的知识,希望对你有一定的参考价值。
题意可能会很绕
一句话:基环树的直径。
求直径:
对于环上每一个点记录其向它的子树最长路径为$dp_x$
之后记录环上边长前缀和$ns_i$
dp值为$max_i,jdp[i]+sum[i]+dp[j]-sum[j]$
$dp[j]-sum[j]$提出来进单调队列。
O(n)。
记得dfs改bfs。
#include<cstdio> #include<algorithm> using namespace std; typedef long long lint; const int N=1145141; template<typename TP>inline void read(TP &kk) TP ret=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘)if(ch==‘-‘)f=-1;ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)ret=ret*10+ch-‘0‘;ch=getchar(); kk=ret*f; int n; struct sumirekoint to,ne,w;e[N*2]; int he[N],ecnt; void addline(int f,int t,int w) e[++ecnt].to=t; e[ecnt].w=w; e[ecnt].ne=he[f]; he[f]=ecnt; bool vv[N],onr[N]; int rnd[N*2],hp,sp,nw[N*2]; lint ns[N*2]; int find(int x,int f) if(vv[x])sp=x;return 1; vv[x]=1;int tmp; for(int i=he[x],t;i;i=e[i].ne) t=e[i].to; if(i==((f&1)?f+1:f-1)) continue; if(tmp=find(t,i)) if(tmp==1) rnd[++hp]=x; onr[x]=1; nw[hp]=e[i].w; if(x!=sp) return 1; return 2; return 0; lint dp[N],ans0,ans1; int h,l; int st[N]; bool use[N]; int fa[N]; void bfs(int u) h = 1,l = 0; st[++l] = u; use[u]=1; while(h<=l) u = st[h++]; for(int j=he[u];j;j=e[j].ne) int to = e[j].to; if(use[to]||onr[to])continue; use[to] = 1; fa[to] = u; st[++l] = to; for(int i=l;i>=1;i--) u = st[i]; for(int j=he[u];j;j=e[j].ne) int to = e[j].to; if(onr[to]||to==fa[u])continue; lint tmp = dp[to]+e[j].w; ans0 = max(ans0,dp[u]+tmp); dp[u]=max(dp[u],tmp); lint ans; int qu[N*2],qh,qt; void fuck(int xx) ans0=ans1=0; hp=0; find(xx,0); int x; for(int i=1;i<=hp;i++) x=rnd[i]; bfs(x); nw[i+hp]=nw[i]; rnd[i+hp]=rnd[i]; for(int i=1;i<=2*hp;i++) ns[i]=ns[i-1]+nw[i]; qh=1,qt=0; for(int i=1;i<2*hp;i++) while(qh<qt&&qu[qh]+hp<=i) qh++; if(qh<=qt)ans1=max(ans1,dp[rnd[i]]+ns[i]+dp[rnd[qu[qh]]]-ns[qu[qh]]); while(qh<=qt&&dp[rnd[qu[qt]]]-ns[qu[qt]]<=dp[rnd[i]]-ns[i]) qt--; qu[++qt]=i; ans+=max(ans0,ans1); hp=0; int xi,yi,wi; signed main() read(n); for(int i=1;i<=n;i++) read(xi),read(wi); addline(i,xi,wi),addline(xi,i,wi); for(int i=1;i<=n;i++) if(!use[i]) fuck(i); printf("%lld\n",ans); return 0;
以上是关于[bzoj1791][ioi2008]Island 岛屿(基环树树的直径)的主要内容,如果未能解决你的问题,请参考以下文章