【JZOJ A組】黑暗之魂(darksoul)
阿新 • • 發佈:2018-11-08
Description
oi_juruo熱愛一款名叫黑暗之魂的遊戲。在這個遊戲中玩家要操縱一名有 點生命值的無火的餘灰在一張地圖中探險。地圖中有n個篝火(也就是存檔點)。在篝火處休息可以將生命值恢復滿。每個篝火都會向其他篝火的其中之一連有一條通道(顯然,通道是雙向的),這些篝火之間都相互可達。也就是說,這是一張n個點,n條邊的無向連通圖。每條通道里都有一些怪物,經過oi_juruo的分析,他得到了每條邊的怪物會對他造成的傷害值 .為了向oier們表演他高超的遊戲技巧,他要從任意一個篝火跑到任意另一個篝火而不在之間的篝火休息,在此期間,他會和他經過的通道中的怪物戰鬥並損失 的生命值。現在oi_juruo想知道,他的生命值 至少為多少,才能完成任意一條旅途。oi_juruo並不傻,他會走最安全的路。本題時限為3000ms
Input
第一行一個整數n。之後n行,每行三個整數ui,vi,ai ,表示有一條從ui 連向vi ,怪物傷害值為ai 的通道。
Output
一行一個數hp,表示無火的餘灰的最小生命值。
Sample Input
5
1 2 2
2 3 2
3 4 2
1 4 1
4 5 4
Sample Output
8
樣例說明
從2到5的路最危險,2 1 4 5受到了7點傷害,所以需要有8點生命值。
Data Constraint
思路
顯然上述方法無法拓展,原因在於將環套樹看成圖而不是一棵略複雜的樹更簡單的仙人掌。環套樹可以視為將森林的根擺在一個環上的產物。顯然,對每棵樹我們可以計算出他的內部直徑,之後只有這棵樹的最長鏈有意義。問題規約為:求一個“刺球”的直徑。暴力計算是O(k2
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #define ll long long using namespace std; const int maxn=1e6+11; int n,cnt,k,bel,tot,head1,tail,boo,list[maxn],dfn[maxn],low[maxn],belong[maxn]; bool vis[maxn]; int root[maxn],q[maxn*2]; ll ans,f[maxn*2],len[maxn*2],pre[maxn*2],dis[maxn*2],mid; struct E{ int v,to,from; }e[maxn*2]; struct A{ int x,y,v; }a[maxn]; vector<int>Q; void insert(int a,int b,int c) { e[++cnt].to=b; e[cnt].from=list[a]; e[cnt].v=c; list[a]=cnt; e[++cnt].to=a; e[cnt].from=list[b]; e[cnt].v=c; list[b]=cnt; } void dfs(int x,int fa) { ll max1=0,max2=0,l=0; for(int i=list[x]; i; i=e[i].from) if(belong[e[i].to]!=k&&e[i].to!=fa) { dfs(e[i].to,x); l=f[e[i].to]+e[i].v; if(l>max1) max2=max1,max1=l; else max2=max(l,max2); } ans=max(max1+max2,ans); f[x]=max1; } void tarjan(int x,int fa) { dfn[x]=low[x]=++cnt,vis[x]=1; Q.push_back(x); for(int i=list[x]; i; i=e[i].from) if(e[i].to!=fa) { if(!dfn[e[i].to]) { tarjan(e[i].to,x); low[x]=min(low[x],low[e[i].to]); } else if(vis[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); } if(low[x]==dfn[x]) { bel++; int y=0,boo=0; if(Q.back()!=x) boo=1,k=bel; while(y!=x) { y=Q.back(),Q.pop_back(); belong[y]=bel,vis[y]=0; if(boo) root[++tot]=y; } } } bool cmp(A a,A b) { return a.x==b.x?(a.y==b.y?a.v<b.v:a.y<b.y):a.x<b.x; } int main() { freopen("darksoul.in","r",stdin); freopen("darksoul.out","w",stdout); scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v); if(a[i].x>a[i].y) swap(a[i].x,a[i].y); } sort(a+1,a+n+1,cmp); bool boo=false; for(int i=1; i<=n; i++) if(a[i].x==a[i].y||a[i].x==a[i-1].x&&a[i].y==a[i-1].y) boo=true; else insert(a[i].x,a[i].y,a[i].v); if(boo) { k=-1,dfs(1,0),printf("%lld",ans+1); return 0; } cnt=0,tarjan(1,0); for(int i=1; i<=tot; i++) dfs(root[i],0),len[i]=f[root[i]]; for(int i=1; i<=tot; i++) for(int j=list[root[i]]; j; j=e[j].from) if(e[j].to==root[i!=1?i-1:tot]) { dis[i]=(ll)e[j].v; break; } for(int i=1; i<=tot; i++) dis[i+tot]=dis[i],len[i+tot]=len[i]; for(int i=1; i<=tot*2; i++) pre[i]=pre[i-1]+dis[i]; mid=pre[tot]; head1=tail=q[head1]=1; for(int i=2; i<=2*tot; i++) { while(head1<=tail&&(pre[i]-pre[q[head1]]>mid/2)) head1++; if(head1<=tail) ans=max(ans,len[q[head1]]+len[i]+pre[i]-pre[q[head1]]); while(head1<=tail&&(len[i]-pre[i]>=len[q[tail]]-pre[q[tail]])) tail--; q[++tail]=i; } printf("%lld",ans+1); }