您的位置:首页 > 其它

BZOJ 1791 [Ioi2008] Island 岛屿

2016-07-05 22:47 465 查看
Description

你将要游览一个有N个岛屿的公园。从每一个岛i出发,只建造一座桥。桥的长度以Li表示。公园内总共有N座桥。尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走。同时,每一对这样的岛屿,都有一艘专用的往来两岛之间的渡船。 相对于乘船而言,你更喜欢步行。你希望所经过的桥的总长度尽可能的长,但受到以下的限制。 • 可以自行挑选一个岛开始游览。 • 任何一个岛都不能游览一次以上。 • 无论任何时间你都可以由你现在所在的岛S去另一个你从未到过的岛D。由S到D可以有以下方法: o 步行:仅当两个岛之间有一座桥时才有可能。对于这种情况,桥的长度会累加到你步行的总距离;或者 o 渡船:你可以选择这种方法,仅当没有任何桥和/或以前使用过的渡船的组合可以由S走到D(当检查是否可到达时,你应该考虑所有的路径,包括经过你曾游览过的那些岛)。 注意,你不必游览所有的岛,也可能无法走完所有的桥。 任务 编写一个程序,给定N座桥以及它们的长度,按照上述的规则,计算你可以走过的桥的最大长度。 限制 2 <= N <= 1,000,000 公园内的岛屿数目。 1<= Li <= 100,000,000 桥i的长度。

【题目分析】

先把环以外的店解决掉,然后把环拆开,复制一遍。用单调栈统计经过环上的最大值。然后把每一个连通块的和加起来。注意:只有两个点的环需要特判。

【代码】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int h[2000001],ne[2000001],to[2000001],w[2000001],en=0;
int bel[1000001],du[1000001];
int vis[1000001];
long long d[1000001];
long long f[1000001];
long long a[2000001],b[2000002];
long long ans=0;
long long q[2000001];
int cnt=1,n;
inline void add(int a,int b,int x)
{to[en]=b;ne[en]=h[a];w[en]=x;h[a]=en++;}
void solve(int k,int num)
{
queue<int>q;
q.push(k);
bel[k]=num;
while (!q.empty())
{
int x=q.front();q.pop();
for (int i=h[x];i>=0;i=ne[i])
if (!bel[to[i]]) bel[to[i]]=num,q.push(to[i]);
}
}
inline void tops()
{
queue<int>q;
for (int i=1;i<=n;++i) if (du[i]==1) q.push(i);
while (!q.empty())
{
int x=q.front();q.pop();
for (int i=h[x];i>=0;i=ne[i])
if (du[to[i]]>1)
{
d[bel[x]]=max(d[bel[x]],f[x]+f[to[i]]+w[i]);
f[to[i]]=max(f[to[i]],f[x]+w[i]);
if ((--du[to[i]])==1) q.push(to[i]);
}
}
}
inline void dp(int be,int k)
{
int y=k,l=0,t=0,p,r;
do{
a[++t]=f[y];
du[y]=1;
for (p=h[y];p>=0;p=ne[p])
if (du[to[p]]>1){
y=to[p],b[t+1]=b[t]+w[p];
break;
}
}while (p!=-1);
if (t==2)
{
for (int i=h[y];i>=0;i=ne[i])
if (to[i]==k) l=max(l,w[i]);
d[be]=max(d[be],f[k]+f[y]+l);
return ;
}
for (int i=h[y];i>=0;i=ne[i])
if (to[i]==k)
{
b[t+1]=b[t]+w[i];
break;
}
for (int i=1;i<t;++i)
{a[t+i]=a[i],b[t+i]=b[t+1]+b[i];}
r=1;l=1;q[1]=1;
for (int i=2;i<2*t;++i)
{
if (l<=r&&i-q[l]>=t) l++;
d[be]=max(d[be],a[i]+a[q[l]]+b[i]-b[q[l]]);
while (l<=r&&a[q[r]]+b[i]-b[q[r]]<=a[i]) r--;
q[++r]=i;
}
return ;
}
int main()
{
memset(h,-1,sizeof h);
memset(ne,-1,sizeof ne);
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
int a,x;
scanf("%d%d",&a,&x);
add(i,a,x),add(a,i,x);
du[i]++,du[a]++;
}
for (int i=1;i<=n;++i)
if (!bel[i]) solve(i,cnt),cnt++;
tops();
for (int i=1;i<=n;++i)
{
if (du[i]>1&&!vis[bel[i]])
{
vis[bel[i]]=1;
dp(bel[i],i);
ans+=d[bel[i]];
}
}
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bzoj