BZOJ1791: [Ioi2008]Island 岛屿
Description
Input
Output
Sample Input
3 8
7 2
4 2
1 4
1 9
3 4
2 3
Sample Output
HINT
题解Here!
- 位于某个子树中且不在环上。即:不经过环上的点。
- 部分经过环,且去掉处于环上的边后位于两颗不同的子树内。即:至少经过环上两个点。
所以我们得把环找出来。
同时求出:从每个环上节点出发在不经过环的前提下的最长链。
这里当然借鉴一下网上大佬得拓扑排序找环辣!
于是这个玩意直接丢给拓扑排序就好。
用求树的直径的方法更新答案处理第一种情况。
对于第二种情况,就等价于从环上找出两点$i,j$使得$dp[i]+dis(i,j)+dp[j]$最大。
$dis(i,j)$为两点在环上的最长距离。
$dp[i]$表示以$i$为根的子树内以一个端点为根的最长链。
记得考虑顺时针和逆时针两种走法。
- #include<iostream>
- #include<algorithm>
- #include<cstdio>
- #define MAXN 1000010
- using namespace std;
- int n,c=1,T=0;
- int head[MAXN],degree[MAXN],colour[MAXN],que[MAXN<<1];
- long long ans=0,dis[MAXN],dp[MAXN],f[MAXN<<1],g[MAXN<<1];
- bool vis[MAXN];
- struct Edge{
- int next,to,w;
- }a[MAXN<<1];
- inline int read(){
- int date=0,w=1;char c=0;
- while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
- while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
- return date*w;
- }
- inline void add(int u,int v,int w){
- a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
- a[c].to=u;a[c].w=w;a[c].next=head[v];head[v]=c++;
- degree[u]++;degree[v]++;
- }
- void bfs(int rt){
- int l=1,r=1,u,v;
- que[1]=rt;
- colour[rt]=T;
- while(l<=r){
- u=que[l];
- for(int i=head[u];i;i=a[i].next){
- v=a[i].to;
- if(!colour[v]){
- que[++r]=v;
- colour[v]=T;
- }
- }
- l++;
- }
- }
- void topsort(){
- int l=1,r=0,u,v;
- for(int i=1;i<=n;i++)if(degree[i]==1)que[++r]=i;
- while(l<=r){
- u=que[l];
- for(int i=head[u];i;i=a[i].next){
- v=a[i].to;
- if(degree[v]>1){
- dis[colour[u]]=max(dis[colour[u]],dp[u]+dp[v]+a[i].w);
- dp[v]=max(dp[v],dp[u]+a[i].w);
- degree[v]--;
- if(degree[v]==1)que[++r]=v;
- }
- }
- l++;
- }
- }
- void solve(int rt,int colour){
- int u,v,m=0;
- u=rt;
- for(int i=1;i;){
- f[++m]=dp[u];
- degree[u]=1;
- for(i=head[u];i;i=a[i].next){
- v=a[i].to;
- if(degree[v]>1){
- g[m+1]=g[m]+a[i].w;
- u=v;
- break;
- }
- }
- }
- if(m==2){
- int len=0;
- for(int i=head[u];i;i=a[i].next)if(a[i].to==rt)len=max(len,a[i].w);
- dis[colour]=max(dis[colour],dp[rt]+dp[u]+len);
- }
- else{
- int l=1,r=1;
- que[1]=1;
- for(int i=head[u];i;i=a[i].next)if(a[i].to==rt){
- g[m+1]=g[m]+a[i].w;
- break;
- }
- for(int i=1;i<m;i++){
- f[m+i]=f[i];
- g[m+i]=g[m+1]+g[i];
- }
- for(int i=2;i<2*m;i++){
- while(l<=r&&i-que[l]>=m)l++;
- dis[colour]=max(dis[colour],f[i]+f[que[l]]+g[i]-g[que[l]]);
- while(l<=r&&f[que[r]]-g[que[r]]<=f[i]-g[i])r--;
- que[++r]=i;
- }
- }
- }
- void work(){
- for(int i=1;i<=n;i++)if(degree[i]>1&&!vis[colour[i]]){
- vis[colour[i]]=true;
- solve(i,colour[i]);
- ans+=dis[colour[i]];
- }
- printf("%lld\n",ans);
- }
- void init(){
- int x,w;
- n=read();
- for(int i=1;i<=n;i++){
- x=read();w=read();
- add(i,x,w);
- }
- for(int i=1;i<=n;i++)if(!colour[i]){T++;bfs(i);}
- topsort();
- }
- int main(){
- init();
- work();
- return 0;
- }
BZOJ1791: [Ioi2008]Island 岛屿的更多相关文章
- [bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)
[bzoj1791][ioi2008]Island 岛屿(基环树.树的直径) bzoj luogu 题意可能会很绕 一句话:基环树的直径. 求直径: 对于环上每一个点记录其向它的子树最长路径为$dp_ ...
- bzoj1791: [Ioi2008]Island 岛屿 单调队列优化dp
1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1826 Solved: 405[Submit][S ...
- bzoj千题计划114:bzoj1791: [Ioi2008]Island 岛屿
http://www.lydsy.com/JudgeOnline/problem.php?id=1791 就是求所有基环树的直径之和 加手工栈 #include<cstdio> #incl ...
- BZOJ1791[Ioi2008]Island 岛屿 ——基环森林直径和+单调队列优化DP+树形DP
题目描述 你将要游览一个有N个岛屿的公园.从每一个岛i出发,只建造一座桥.桥的长度以Li表示.公园内总共有N座桥.尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走.同时,每一对这样的岛屿,都有一 ...
- [BZOJ1791][IOI2008]Island岛屿(环套树DP)
同NOI2013快餐店(NOI出原题?),下面代码由于BZOJ栈空间过小会RE. 大致是对每个连通块找到环,在所有内向树做一遍DP,再在环上做两遍前缀和优化的DP. #include<cstdi ...
- bzoj1791[IOI2008]Island岛屿(基环树+DP)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1791 题目大意:给你一棵n条边的基环树森林,要你求出所有基环树/树的直径之和.n< ...
- BZOJ1791 [Ioi2008]Island 岛屿[基环树+单调队列优化DP]
基环树直径裸题. 首先基环树直径只可能有两种形式:每棵基环树中的环上挂着的树的直径,或者是挂在环上的两个树的最大深度根之间的距离之和. 所以,先对每个连通块跑一遍,把环上的点找出来,然后对环上每个点跑 ...
- 【BZOJ 1791】 [Ioi2008]Island 岛屿
Description 你将要游览一个有N个岛屿的公园.从每一个岛i出发,只建造一座桥.桥的长度以Li表示.公园内总共有N座桥.尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走.同时,每一对这样 ...
- bzoj 1791: [Ioi2008]Island 岛屿
#include<iostream> #include<cstdio> #define M 1000009 using namespace std; *M],cnt,n,hea ...
随机推荐
- 【Android高级】NDK/JNI编程技术基础介绍
作为一个Andoird的Java程序猿,会受到Java语言的局限.由于作为一面门向对象的语言不能像C/C++那样轻易调用与硬件有关的操作.因此JNI就搭建了这样一个桥梁,使Java和C/C++语言之间 ...
- 解决dubbo问题:forbid consumer(2)
线下环境经常出现类似这种异常: com.alibaba.dubbo.rpc.RpcException: Forbid consumer 10.0.53.69 access service com.ku ...
- zoj 3888 Twelves Monkeys 二分+线段树维护次小值
链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do? problemCode=3888 Twelves Monkeys Time Limit: 5 ...
- NHibernate利用Mindscape.NHibernateModelDesigner实现数据库与实体之间的转换及操作
环境:   Visual Studio 2010 一.Mindscape.NhibernateModelDesigner安装   在打开 ...
- windows上IIS实现https,配置ssl证书
windows2012实现IIS7的https 1.申请证书,这里申请腾讯云的证书 1)登录腾讯云控制台,依次单击“云产品”>“SSL证书管理”>“申请证书” 2)在免费证书申请页面填写相 ...
- Squid 启动/停止/重载配置文件 命令
当你的 squid.conf 配置文档按照你的想法修改完以后,启动 squid 之旅就开始了. Squid安装设试命令: 1,初始化你在 squid.conf 里配置的 cache 目录 #/usr/ ...
- MySQL四-1:数据类型
阅读目录 一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型 一 介绍 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 ...
- shell脚本中8种字符串截取方法_转自脚本之家
转自:http://www.jb51.net/article/56563.htm 参考:http://blog.csdn.net/taiyang1987912/article/details/3955 ...
- Tautology - poj 3295
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10437 Accepted: 3963 Description WF ...
- Java多线程中的竞争条件、锁以及同步的概念
竞争条件 1.竞争条件: 在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生“竞争条件”的现象.这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作 ...