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的长度。
【题目分析】
先把环以外的店解决掉,然后把环拆开,复制一遍。用单调栈统计经过环上的最大值。然后把每一个连通块的和加起来。注意:只有两个点的环需要特判。
【代码】
你将要游览一个有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); }
相关文章推荐
- BZOJ3275 Number (最小割)
- BZOJ2809——[Apio2012]dispatching
- BZOJ2809——[Apio2012]dispatching
- [bzoj1003] [ZJOI2006]物流运输trans
- [bzoj1500][NOI2005]维修数列
- [bzoj1208] [HNOI2004]宠物收养所
- [bzoj1269][AHOI2006]文本编辑器editort
- [bzoj1503][NOI2004]郁闷的出纳员
- bzoj4305 数学
- bzoj3926 广义后缀自动机
- bzoj2780 广义后缀自动机+parent树+Dfs序+树状数组
- BZOJ1997 2-sat
- bzoj4027 贪心
- [BZOJ2038][2009国家集训队][莫队][分块]小z的袜子
- [BZOJ2594][WC2006][LCT][MST]水管局长数据加强版
- [BZOJ2300][HAOI2011][动态凸包]防线修建
- [BZOJ1045][HAOI2008][贪心]糖果传递
- [BZOJ2539][CTSC2000][KM]丘比特的烦恼
- [BZOJ1004][HNOI2008][Burnside引理][DP]Cards
- [BZOJ1202][HNOI2005][并查集]狡猾的商人