1. 程式人生 > >BZOJ1791: [Ioi2008]Island 島嶼

BZOJ1791: [Ioi2008]Island 島嶼

return lld 連通 兩個 getc cst sca align 題解

【傳送門:BZOJ1791】


簡要題意:

  給出一張有n個點的圖,有n條雙向邊,長度為Li

  每個點只能走一次

  一個人可以到另一個連通塊當且僅當現在所在的點所有與它相連的點都被走過,那麽他就可以到另一個連通塊的任意一個點

  這個人可以從任意一個點開始行走

  求出最大行走的邊的長度和


題解:

  就是求基環樹森林的直徑和

  對於一棵基環樹,它的直徑有三種情況:

  1.是環上的點的子樹的直徑

  2.是環上兩個點的子樹和+兩個點的最大距離

  前者直接深搜,後者用單調隊列維護求最大即可

  寫一波手工棧就過去了


參考代碼:

#include<cstdio>
#include
<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; typedef long long LL; struct node { int x,y,d,next; }a[2100000];int len,last[1100000]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; }
int tot,s[1100000],X,Y,K; bool get_s(int x,int kk) { if(x==Y) return true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(k==kk||k==(kk^1)||k==K||k==(K^1)) continue; if(get_s(y,k)==true){s[++tot]=k;return true;} } return false; } LL d[1100000],C[1100000],D[1100000
],ans,mmax; bool bo[1100000]; int v[1100000]; /* void getc(int x) { v[x]=true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(v[y]==true) continue; getc(y); if(bo[y]==false) { ans=max(ans,D[x]+D[y]+a[k].d); D[x]=max(D[x],D[y]+a[k].d); } } }*/ int stack[1100000],cur[1100000],f[1100000]; void getc(int x) { int tmp=0;stack[++tmp]=x; v[x]=0;cur[x]=last[x]; while(tmp!=0) { x=stack[tmp]; while(cur[x]!=0&&v[a[cur[x]].y]!=-1) cur[x]=a[cur[x]].next; if(cur[x]==0) { tmp--; if(f[x]!=0) { ans=max(ans,D[f[x]]+D[x]+v[x]); D[f[x]]=max(D[f[x]],D[x]+v[x]); } continue; } int y=a[cur[x]].y;cur[y]=last[y];stack[++tmp]=y; if(bo[y]==false) { v[y]=a[cur[x]].d; f[y]=x; } else v[y]=0; cur[x]=a[cur[x]].next; } } int q[2100000],p[1100000]; int bak(int x){return (x-1)%tot+1;} LL getd(int x) { if(x<=tot) return d[x]; else return d[tot+1]+d[x-tot]; } LL solve() { d[1]=0;mmax=0; for(int i=1;i<=tot;i++) { d[i+1]=a[s[i]].d+d[i]; s[i]=a[s[i]].y; bo[s[i]]=true; } s[++tot]=X;bo[X]=true;d[tot+1]=a[K].d+d[tot]; ans=0; getc(s[1]); mmax=max(ans,mmax); int l=1,r=1;q[l]=1; for(int i=2;i<=2*tot;i++) { while(l<=r&&i-q[l]>=tot) l++; if(l<=r) mmax=max(mmax,D[s[bak(q[l])]]+D[s[bak(i)]]+getd(i)-getd(q[l])); while(l<=r&&D[s[bak(q[r])]]-getd(q[r])<=D[s[bak(i)]]-getd(i)) r--; q[++r]=i; } return mmax; } int fa[1100000]; int findfa(int x) { if(fa[x]!=x) fa[x]=findfa(fa[x]); return fa[x]; } int main() { int n; scanf("%d",&n); len=1;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=n;i++) { int x,d; scanf("%d%d",&x,&d); ins(i,x,d);ins(x,i,d); int fx=findfa(x),fy=findfa(i); if(fx==fy) p[fx]=len; else { fa[fx]=fy; if(p[fx]!=0) p[fy]=p[fx]; } } for(int i=1;i<=n;i++) fa[i]=findfa(i); memset(bo,false,sizeof(bo)); LL ans=0; memset(v,-1,sizeof(v)); for(int i=1;i<=n;i++) { if(fa[i]==i) { tot=0;X=a[p[i]].x;Y=a[p[i]].y;K=p[i]; get_s(X,0); ans+=solve(); } } printf("%lld\n",ans); return 0; }

BZOJ1791: [Ioi2008]Island 島嶼