日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

bzoj1791: [Ioi2008]Island 岛屿 单调队列优化dp

發(fā)布時間:2025/3/21 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 bzoj1791: [Ioi2008]Island 岛屿 单调队列优化dp 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1791: [Ioi2008]Island 島嶼

Time Limit:?20 Sec??Memory Limit:?162 MB
Submit:?1826??Solved:?405
[Submit][Status][Discuss]

Description

你將要游覽一個有N個島嶼的公園。從每一個島i出發(fā),只建造一座橋。橋的長度以Li表示。公園內(nèi)總共有N座橋。盡管每座橋由一個島連到另一個島,但每座橋均可以雙向行走。同時,每一對這樣的島嶼,都有一艘專用的往來兩島之間的渡船。 相對于乘船而言,你更喜歡步行。你希望所經(jīng)過的橋的總長度盡可能的長,但受到以下的限制。 ? 可以自行挑選一個島開始游覽。 ? 任何一個島都不能游覽一次以上。 ? 無論任何時間你都可以由你現(xiàn)在所在的島S去另一個你從未到過的島D。由S到D可以有以下方法: o 步行:僅當(dāng)兩個島之間有一座橋時才有可能。對于這種情況,橋的長度會累加到你步行的總距離;或者 o 渡船:你可以選擇這種方法,僅當(dāng)沒有任何橋和/或以前使用過的渡船的組合可以由S走到D(當(dāng)檢查是否可到達(dá)時,你應(yīng)該考慮所有的路徑,包括經(jīng)過你曾游覽過的那些島)。 注意,你不必游覽所有的島,也可能無法走完所有的橋。 任務(wù) 編寫一個程序,給定N座橋以及它們的長度,按照上述的規(guī)則,計算你可以走過的橋的最大長度。 限制 2 <= N <= 1,000,000 公園內(nèi)的島嶼數(shù)目。 1<= Li <= 100,000,000 橋i的長度。

Input

? 第一行包含N個整數(shù),即公園內(nèi)島嶼的數(shù)目。島嶼由1到N編號。 ? 隨后的N行每一行用來表示一個島。第i 行由兩個以單空格分隔的整數(shù),表示由島i筑的橋。第一個整數(shù)表示橋另一端的島,第二個整數(shù)表示該橋的長度Li。你可以假設(shè)對於每座橋,其端點總是位于不同的島上。

Output

你的程序必須向標(biāo)準(zhǔn)輸出寫出包含一個整數(shù)的單一行,即可能的最大步行距離。 注1:對某些測試,答案可能無法放進(jìn)32-bit整數(shù),你要取得這道題的滿分,可能需要用Pascal的int64或C/C++的long long類型。 注2:在比賽環(huán)境運行Pascal程序,由標(biāo)準(zhǔn)輸入讀入64-bit數(shù)據(jù)比32-bit數(shù)據(jù)要慢得多,即使被讀取的數(shù)據(jù)可以32-bit表示。我們建議把輸入數(shù)據(jù)讀入到32-bit數(shù)據(jù)類型。 評分 N不會超過4,000。

Sample Input

7
3 8
7 2
4 2
1 4
1 9
3 4
2 3


Sample Output

24

HINT

Source

題目理解一下就變成了求多棵基環(huán)外向樹直徑的和

對于任意一棵基環(huán)外向樹,可以先對于環(huán)上每個點i做一個樹形dp求出i向外延伸的最大距離

如果直徑不經(jīng)過環(huán) 那么在做樹形dp的時候就可以找出來

如果經(jīng)過環(huán),那么在環(huán)上dp:

把每個點向外延伸的最大距離當(dāng)成點權(quán),問題即轉(zhuǎn)化為求環(huán)上兩點i,j 要求dis(i,j)+v[i]+v[j]最大

把無向環(huán)看作有向環(huán),即把序列倍增一次補在后面,這樣即可實現(xiàn)單方向轉(zhuǎn)移

單調(diào)隊列維護(hù)轉(zhuǎn)移,在轉(zhuǎn)移長度達(dá)到環(huán)長的時候head++

http://blog.csdn.net/vmurder/article/details/38940815

?

我寫錯了很多地方:

1.維護(hù)單調(diào)隊列單調(diào)性時求兩點距離錯了

2.先沒想到直徑可以不經(jīng)過環(huán)

3.數(shù)組爆掉

4.爆棧

前面3點在經(jīng)過3h的調(diào)試之后更正了

第四點無法優(yōu)化,因為bzoj好像不讓自己擴棧?

?

爆棧這個問題,其實可以避免

我是dfs找環(huán) 再dfs環(huán)求dp? (不炸成瓜皮才怪)

看了看網(wǎng)上更優(yōu)的方法,可以先求每個聯(lián)通塊,然后對聯(lián)通塊topsort,topsort的時候順便轉(zhuǎn)移dp

感覺自己宛如一個zz,又忘記了topsort求環(huán)

下面是我的代碼? 1 #include<bits/stdc++.h> 2 #define N 1000005 3 #define ll long long 4 #pragma comment(linker, "/STACK:102400000,102400000") 5 using namespace std; 6 int n,tot,cnt,tp,fg,num,siz[N],s[N],q[N<<1],hd[N]; 7 int cir[N],bl[N],g[N<<1],d[N<<1],vis[N]; 8 ll len,ans[N],f[N],dis[N<<1],dp[N]; 9 struct edge{int v,w,next;}e[N<<1]; 10 void adde(int u,int v,int w){ 11 e[++tot].v=v; 12 e[tot].w=w; 13 e[tot].next=hd[u]; 14 hd[u]=tot; 15 } 16 void dfs1(int u,int fa){ 17 if(vis[u]&&!bl[u]){ 18 cir[++cnt]=u; 19 int tmp=s[tp]; 20 while(1){ 21 bl[tmp]=cnt;--tp; 22 ++siz[cnt]; 23 if(tmp==u)break; 24 tmp=s[tp]; 25 } 26 return; 27 } 28 if(vis[u])return; 29 vis[u]=1;s[++tp]=u; 30 int tmp=0; 31 for(int i=hd[u];i;i=e[i].next){ 32 int v=e[i].v; 33 if(v==fa&&!tmp){tmp=1;continue;} 34 dfs1(v,u); 35 } 36 --tp; 37 } 38 void getdp(int u,int fa,int id){ 39 ll m1=0,m2=0,res; 40 for(int i=hd[u];i;i=e[i].next){ 41 int v=e[i].v; 42 if(v==fa||bl[v]==id)continue; 43 getdp(v,u,id);res=e[i].w+dp[v]; 44 dp[u]=max(dp[u],res); 45 if(res>m1)m2=m1,m1=res; 46 else if(res>m2)m2=res; 47 } 48 ans[id]=max(ans[id],m1+m2); 49 } 50 inline ll getd(int i,int j){ 51 return dis[j]-dis[i]; 52 } 53 54 void solve(int id){ 55 ll &mx=ans[id];int L=siz[id],tid=num; 56 for(int i=1;i<=num;++i) 57 g[++tid]=g[i],d[tid]=d[i],dis[tid]=dis[i]; 58 int h=1,t=1;q[1]=1;mx=max(dp[g[1]],mx); 59 for(int i=2;i<tid;++i){ 60 while(h<t&&i-q[h]>=L)h++; 61 if(i>num&&q[h]>num)break; 62 if(i>num)f[i]=len-dis[q[h]]+dp[g[q[h]]]+dp[g[i]]+dis[i]; 63 else f[i]=dis[i]-dis[q[h]]+dp[g[q[h]]]+dp[g[i]]; 64 mx=max(f[i],mx);if(i>num)continue; 65 while(h<=t&&dp[g[q[t]]]+getd(q[t],i)<=dp[g[i]])t--;q[++t]=i; 66 } 67 } 68 void dfs2(int u,int fa,int id){ 69 if(u==cir[id]&&fa){ 70 solve(id);fg=1; 71 return; 72 } 73 g[++num]=u;getdp(u,0,id);int tmp=0; 74 for(int i=hd[u];i&&!fg;i=e[i].next){ 75 int v=e[i].v; 76 if(bl[v]!=id)continue; 77 if(v==fa&&!tmp){tmp=1;continue;} 78 if(v!=cir[id]){ 79 dis[num+1]=dis[num]+e[i].w; 80 d[num+1]=e[i].w; 81 } 82 else d[1]=e[i].w; 83 len+=e[i].w;dfs2(v,u,id); 84 } 85 } 86 int main(){ 87 scanf("%d",&n); 88 for(register int i=1;i<=n;++i){ 89 int v,w; 90 scanf("%d%d",&v,&w); 91 adde(i,v,w);adde(v,i,w); 92 } 93 for(register int i=1;i<=n;i++) 94 if(!vis[i])tp=0,dfs1(i,0); 95 for(register int i=1;i<=cnt;i++){ 96 len=0;fg=0;num=0;dis[1]=0; 97 dfs2(cir[i],0,i); 98 } 99 ll all=0; 100 for(register int i=1;i<=cnt;i++)all+=ans[i]; 101 printf("%lld\n",all); 102 return 0; 103 } 爆棧dfs

?

然后是網(wǎng)上一個人的代碼? 用的topsort

1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <queue> 7 #define M 1000005 8 #define LL long long 9 using namespace std; 10 struct edge 11 { 12 int y,ne,v; 13 }e[M*2]; 14 int h[M],v[M],c[M],du[M],q[2*M],n,m,tot,t; 15 LL f[M],d[M],a[2*M],b[2*M]; 16 void Addedge(int x,int y,int v) 17 { 18 tot++; 19 e[tot].y=y; 20 e[tot].ne=h[x]; 21 h[x]=tot; 22 e[tot].v=v; 23 du[x]++; 24 } 25 void dfs(int x,int k) 26 { 27 v[x]=1,c[x]=k; 28 for (int i=h[x];i;i=e[i].ne) 29 { 30 int y=e[i].y; 31 if (v[y]) continue; 32 dfs(y,k); 33 } 34 } 35 void Topsort() 36 { 37 int l=1,r=0,y; 38 for (int i=1;i<=n;i++) 39 if (du[i]==1) q[++r]=i; 40 while (l<=r) 41 { 42 int x=q[l]; 43 for (int i=h[x];i;i=e[i].ne) 44 if (du[y=e[i].y]>1) 45 { 46 du[y]--; 47 d[c[x]]=max(d[c[x]],f[x]+f[y]+e[i].v); 48 f[y]=max(f[y],f[x]+e[i].v); 49 if (du[y]==1) q[++r]=y; 50 } 51 l++; 52 } 53 } 54 void Dp(int t,int x) 55 { 56 int m=0,i,y=x; 57 do 58 { 59 a[++m]=f[y],du[y]=1; 60 for (i=h[y];i;i=e[i].ne) 61 if (du[e[i].y]>1) 62 { 63 y=e[i].y; 64 b[m+1]=b[m]+e[i].v; 65 break; 66 } 67 }while (i); 68 if (m==2) 69 { 70 int l=0; 71 for (int i=h[y];i;i=e[i].ne) 72 if (e[i].y==x) l=max(l,e[i].v); 73 d[t]=max(d[t],f[x]+f[y]+l); 74 return; 75 } 76 for (int i=h[y];i;i=e[i].ne) 77 if (e[i].y==x) 78 { 79 b[m+1]=b[m]+e[i].v; 80 break; 81 } 82 for (int i=1;i<=m;i++) 83 { 84 a[m+i]=a[i]; 85 b[m+i]=b[m+1]+b[i]; 86 } 87 int l,r; 88 q[l=r=1]=1; 89 for (int i=2;i<2*m;i++) 90 { 91 while (l<=r&&i-q[l]>=m) 92 l++; 93 d[t]=max(d[t],a[i]+a[q[l]]+b[i]-b[q[l]]); 94 while (l<=r&&a[q[r]]+b[i]-b[q[r]]<=a[i]) 95 r--; 96 q[++r]=i; 97 } 98 } 99 int main() 100 { 101 scanf("%d",&n); 102 for (int i=1;i<=n;i++) 103 { 104 int x,y; 105 scanf("%d%d",&x,&y); 106 Addedge(x,i,y); 107 Addedge(i,x,y); 108 } 109 memset(v,0,sizeof(v)); 110 t=0; 111 for (int i=1;i<=n;i++) 112 if (!c[i]) dfs(i,++t); 113 Topsort(); 114 LL ans=0LL; 115 memset(v,0,sizeof(v)); 116 for (int i=1;i<=n;i++) 117 if (du[i]>1&&!v[c[i]]) 118 { 119 v[c[i]]=1; 120 Dp(c[i],i); 121 ans+=d[c[i]]; 122 } 123 cout<<ans<<endl; 124 return 0; 125 } topsort

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/wsy01/p/8135697.html

總結(jié)

以上是生活随笔為你收集整理的bzoj1791: [Ioi2008]Island 岛屿 单调队列优化dp的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。