JZOJ 5905. 【NOIP2018模拟10.15】黑暗之魂(darksoul)
Description
oi_juruo熱愛一款名叫黑暗之魂的游戲。在這個(gè)游戲中玩家要操縱一名有 點(diǎn)生命值的無火的余灰在一張地圖中探險(xiǎn)。地圖中有n個(gè)篝火(也就是存檔點(diǎn))。在篝火處休息可以將生命值恢復(fù)滿。每個(gè)篝火都會(huì)向其他篝火的其中之一連有一條通道(顯然,通道是雙向的),這些篝火之間都相互可達(dá)。也就是說,這是一張n個(gè)點(diǎn),n條邊的無向連通圖。每條通道里都有一些怪物,經(jīng)過oi_juruo的分析,他得到了每條邊的怪物會(huì)對他造成的傷害值 .為了向oier們表演他高超的游戲技巧,他要從任意一個(gè)篝火跑到任意另一個(gè)篝火而不在之間的篝火休息,在此期間,他會(huì)和他經(jīng)過的通道中的怪物戰(zhàn)斗并損失 的生命值。現(xiàn)在oi_juruo想知道,他的生命值 至少為多少,才能完成任意一條旅途。oi_juruo并不傻,他會(huì)走最安全的路。本題時(shí)限為3000ms
Input
第一行一個(gè)整數(shù)n。之后n行,每行三個(gè)整數(shù)ui,vi,ai ,表示有一條從ui 連向vi ,怪物傷害值為ai 的通道。
Output
一行一個(gè)數(shù)hp,表示無火的余灰的最小生命值。
Sample Input
5
1 2 2
2 3 2
3 4 2
1 4 1
4 5 4
Sample Output
8
樣例說明
從2到5的路最危險(xiǎn),2 1 4 5受到了7點(diǎn)傷害,所以需要有8點(diǎn)生命值。
Data Constraint
Solution
-
由題知這是一顆環(huán)套樹(n點(diǎn)n邊,環(huán)大小≥1\geq1≥1)。
-
題目要求的是這棵環(huán)套樹的直徑,再+1就是答案了。
-
我們把該環(huán)提出來,在上面操作。
-
那么直徑要么是環(huán)上某點(diǎn)的子樹內(nèi)直徑,要么是環(huán)上某兩點(diǎn)子樹內(nèi)最長鏈再加一段環(huán)上路徑。
-
子樹內(nèi)直徑和最長鏈我們先算出來,剩下的就是如何求出環(huán)上兩點(diǎn)使之匹配出來最大值。
-
枚舉環(huán)上一點(diǎn) iii,同時(shí)維護(hù)一個(gè)指針 jjj 往后指,表示從 i+1i+1i+1 到 jjj 是近一些,而 jjj 之后的點(diǎn)呢會(huì)繞環(huán)一圈來走回 iii 更近一些。
-
那么 i+1i+1i+1 到 jjj 的我們用一個(gè)單調(diào)隊(duì)列來求最大值,繞一周的用一個(gè)后綴最大值算就好了。
-
時(shí)間復(fù)雜度 O(n)O(n)O(n) ,但常數(shù)有些大。
Code
#include<cstdio> #include<cctype> using namespace std; typedef long long LL; const int N=1e6+5; int tot=1,top,qx,qy,node; LL ans,mx; bool pd; int first[N],nex[N<<1],en[N<<1],w[N<<1]; int st[N],dfn[N],d[N],len[N],col[N],q[N]; LL suf[N],pre[N],f[N]; bool bz[N]; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48),ch=getchar();return w?-X:X; } inline LL max(LL x,LL y) {return x>y?x:y; } inline void insert(int x,int y,int z) {nex[++tot]=first[x];first[x]=tot;en[tot]=y;w[tot]=z; } void dfs(int x,int y) {st[++top]=x;dfn[x]=top;for(int i=first[x];i && !pd;i=nex[i])if(i^y){if(dfn[en[i]]){for(int j=dfn[en[i]];j<=top;j++){d[++d[0]]=st[j];bz[st[j]]=true;}pd=true;return;}dfs(en[i],i^1);}top--; } void find(int x,int y,LL z,LL &num) {if(z>num) num=z;for(int i=first[x];i;i=nex[i])if(en[i]^y && en[i]^x) find(en[i],x,z+w[i],num); } void get(int x,int y) {if(y==d[0]) return;for(int i=first[x];i;i=nex[i])if(en[i]==d[y+1]){len[y]=w[i];get(en[i],y+1);} } void dg(int x,int y,LL z) {if(z>mx) mx=z,node=x;col[x]=tot;for(int i=first[x];i;i=nex[i])if(en[i]^y && en[i]^x && !bz[en[i]]) dg(en[i],x,z+w[i]); } void dg1(int x,int y,LL z) {if(z>mx) mx=z,node=x;for(int i=first[x];i;i=nex[i])if(en[i]^y && en[i]^x && col[en[i]]==tot) dg1(en[i],x,z+w[i]); } int main() {freopen("darksoul.in","r",stdin);freopen("darksoul.out","w",stdout);int n=read();for(int i=1;i<=n;i++){int x=read(),y=read(),z=read();insert(x,y,z);insert(y,x,z);}dfs(1,0);tot=0;for(int i=1;i<=d[0];i++){for(int j=first[d[i]];j;j=nex[j])if(!bz[en[j]]) find(en[j],d[i],w[j],f[i]);node=mx=0;tot++;dg(d[i],0,0);dg1(node,0,0);ans=max(ans,mx);if(f[i]>ans) ans=f[i];}get(d[1],1);for(int i=first[d[d[0]]];i;i=nex[i])if(en[i]==d[1]){len[d[0]]=w[i];break;}for(int i=2;i<=d[0];i++) pre[i]=pre[i-1]+len[i-1];for(int i=2;i<=d[0];i++) suf[i]=pre[d[0]]+len[d[0]]-pre[i]+f[i];for(int i=d[0]-1;i>1;i--) suf[i]=max(suf[i+1],suf[i]);int l=1,r=0;for(int i=1,j=1;i<d[0];i++){while(l<r && q[l]<=i) l++;while(j<d[0] && pre[j+1]-pre[i]<=pre[d[0]]-pre[j+1]+len[d[0]]+pre[i]){j++;while(l<=r && f[q[r]]+pre[q[r]]<=f[j]+pre[j]) r--; q[++r]=j;}LL num=0;if(j<d[0]) num=suf[j+1]+pre[i];if(i<j) num=max(num,f[q[l]]+pre[q[l]]-pre[i]);ans=max(ans,num+f[i]);}printf("%lld",ans+1);return 0; }總結(jié)
以上是生活随笔為你收集整理的JZOJ 5905. 【NOIP2018模拟10.15】黑暗之魂(darksoul)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5907. 【NOIP2018
- 下一篇: JZOJ 5923. 【NOIP2018