[bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)
[bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)
题意可能会很绕
一句话:基环树的直径。
求直径:
对于环上每一个点记录其向它的子树最长路径为$dp_x$
之后记录环上边长前缀和$ns_i$
dp值为$max_{i,j}dp[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 sumireko{int 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; }