bzoj1791
1791: [Ioi2008]Island 岛屿
Time Limit: 20 Sec Memory Limit: 162 MB
Submit: 1680 Solved: 369
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
3 8
7 2
4 2
1 4
1 9
3 4
2 3
Sample Output
HINT
Source
这个图跟信息传递很像,也就是一个基环树,但是我很思博地没看出来。。。
事实上这是一个基环树森林,我们要求的是每棵基环树的直径(不太准确),也就是基环树上最长的路径
首先得找到环,这里我们可以分两种情况
1.这条路径在环上,那么也就是说两个端点在环上某个顶点的子树里或环上,那么这个样子可以这么计算:dis=d子树1+d子树2+d环,我们先把环拉开复制一遍接在后面,然后对于环上每个顶点的子树计算一下子树最深的地方到环上该点的距离,这些子树取个最大值。然后就可以dp了dp[i] = max(dp[i], d[i]-d[j]) 这里可以用单调队列优化,具体看代码
2.最长路径位于环上某个顶点的子树里,或者跨越某个顶点的两颗子树。这里就是一个树形dp,代码里写的不清楚,其实就是求树的直径的代码。
吐槽:写了4个小时,忽略了好几种情况,竟然还会爆栈,我不会写手工栈。。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = ;
struct edge {
int nxt, w, to;
} e[N << ];
vector<int> route;
int n, cnt = , pos;
ll ans, Max;
int used[N], vis[N], head[N], mark[N], w[N], prev[N], pree[N << ];
ll mx[N], d[N << ], g[N], q[N], dp[N];
inline int read()
{
int x = , f = ; char c = getchar();
while(c < '' || c > '') { if(c == '-') f = -; c = getchar(); }
while(c >= '' && c <= '') { x *= ; x += c - ''; c = getchar(); }
return x * f;
}
inline void link(int u, int v, int w)
{
e[++cnt].nxt = head[u];
head[u] = cnt;
e[cnt].to = v;
e[cnt].w = w;
}
void Dp(int u, int last)
{
ll Max1 = , Max2 = ;
for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last)
{
Dp(e[i].to, u);
if(g[e[i].to] + (ll)e[i].w >= Max1)
{
Max2 = Max1;
Max1 = g[e[i].to] + (ll)e[i].w;
}
else if(g[e[i].to] + (ll)e[i].w > Max2) Max2 = g[e[i].to] + (ll)e[i].w;
Max = max(Max, Max1 + Max2);
}
g[u] = Max1;
}
bool getcir(int u, int last)
{
vis[u] = ; bool flag = false;
for(int i = head[u]; i; i = e[i].nxt)
{
if(e[i].to == last && !flag) { flag = true; continue; }
if(!vis[e[i].to])
{
prev[e[i].to] = u; pree[e[i].to] = i;
if(getcir(e[i].to, u)) return true;
}
else { pree[e[i].to] = i; pos = u; prev[e[i].to] = u; return true; }
}
return false;
}
void dfs(int u)
{
used[u] = ;
for(int i = head[u]; i; i = e[i].nxt) if(!used[e[i].to]) dfs(e[i].to);
}
void solve(int u)
{
route.clear();
getcir(u, );
for(int now = pos; !mark[now]; now = prev[now])
{
mark[now] = ;
route.push_back(now); w[now] = e[pree[now]].w;
}
for(int i = ; i < route.size(); ++i)
{
ll Max1 = , Max2 = ;
for(int j = head[route[i]]; j; j = e[j].nxt) if(!mark[e[j].to])
{
Dp(e[j].to, route[i]);
if(g[e[j].to] + (ll)e[j].w >= Max1) { Max2 = Max1; Max1 = g[e[j].to] + e[j].w; }
else if(g[e[j].to] + e[j].w > Max2) Max2 = g[e[j].to] + e[j].w;
mx[route[i]] = max(mx[route[i]], g[e[j].to] + (ll)e[j].w);
dp[route[i]] = max(dp[route[i]], max(Max, Max1 + Max2)); Max = ;
}
}
int lim = route.size(), l = , r = ;
for(int i = ; i < lim; ++i) route.push_back(route[i]);
d[] = q[l] = ;
for(int i = ; i < route.size(); ++i) d[i + ] = d[i] + w[route[i]];
ll delta = mx[route[]] + d[];
for(int i = ; i < route.size(); ++i)
{
while(q[r] - q[l] + >= lim && l <= r) ++l;
if(i) delta = max(delta, mx[route[i]] + d[i] + mx[route[q[l]]] - d[q[l]]);
delta = max(delta, dp[route[i]]);
ll x = mx[route[i]] - d[i];
while(l <= r) if(x > mx[route[q[r]]] - d[q[r]]) --r; else break;
q[++r] = i;
}
ans += delta;
dfs(u);
}
int main()
{
// int size = 50 << 20; // 256MB
// char *p = (char*)malloc(size) + size;
// __asm__("movl %0, %%esp\n" :: "r"(p));
freopen("isl.in", "r", stdin);
freopen("isl.out", "w", stdout);
n = read();
for(int i = ; i <= n; ++i)
{
int u, w; u = read(); w = read();
link(i, u, w); link(u, i, w);
}
for(int i = ; i <= n; ++i) if(!used[i]) solve(i);
printf("%lld\n", ans);
fclose(stdin); fclose(stdout);
return ;
}
bzoj1791的更多相关文章
- 【bzoj1791】岛屿
[bzoj1791]岛屿 题意 求基环树的直径. \(n\leq 100000\) 分析 这道题的题解貌似很少啊. 所以自己也写一份吧. 首先找出基环树的环. 那么树的直径有两种情况: ①以环为根的某 ...
- [BZOJ1791][IOI2008]Island岛屿(环套树DP)
同NOI2013快餐店(NOI出原题?),下面代码由于BZOJ栈空间过小会RE. 大致是对每个连通块找到环,在所有内向树做一遍DP,再在环上做两遍前缀和优化的DP. #include<cstdi ...
- BZOJ1791: [Ioi2008]Island 岛屿
BZOJ1791: [Ioi2008]Island 岛屿 Description 你将要游览一个有N个岛屿的公园. 从每一个岛i出发,只建造一座桥. 桥的长度以Li表示. 公园内总共有N座桥. 尽管每 ...
- BZOJ1791 基环树直径
非递归版4S /************************************************************** Problem: 1791 User: 18357 Lan ...
- [IOI2008/BZOJ1791 岛屿](处理基环树的小技巧&基于bfs树形DP)
IOI2008/BZOJ1791 岛屿 题目大意是在一个基环树森林里求每一棵基环树的直径①的和. 其实就是树的直径的基环树升级版.我们先把环找出来,然后从环上的每一个节点x出发,并且不经过环上其他节点 ...
- [bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)
[bzoj1791][ioi2008]Island 岛屿(基环树.树的直径) bzoj luogu 题意可能会很绕 一句话:基环树的直径. 求直径: 对于环上每一个点记录其向它的子树最长路径为$dp_ ...
- 【BZOJ1791】【IOI2008】【基环树】island(status第一速度)
1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 908 Solved: 159 [Su ...
- bzoj1791: [Ioi2008]Island 岛屿 单调队列优化dp
1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 1826 Solved: 405[Submit][S ...
- bzoj1791[IOI2008]Island岛屿(基环树+DP)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1791 题目大意:给你一棵n条边的基环树森林,要你求出所有基环树/树的直径之和.n< ...
- BZOJ1791[Ioi2008]Island 岛屿 ——基环森林直径和+单调队列优化DP+树形DP
题目描述 你将要游览一个有N个岛屿的公园.从每一个岛i出发,只建造一座桥.桥的长度以Li表示.公园内总共有N座桥.尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走.同时,每一对这样的岛屿,都有一 ...
随机推荐
- Leetcode 166.分数到小数
分数到小数 给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数. 如果小数部分为循环小数,则将循环的部分括在括号内. 示例 1: 输入: num ...
- 九度oj 题目1074:对称平方数
题目1074:对称平方数 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6422 解决:2912 题目描述: 打印所有不超过n(n<256)的,其平方具有对称性质的数. 如11*11 ...
- [SCOI2008]奖励关 - 状压动规 - 概率与期望
Description 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝 ...
- android开发里跳过的坑——onActivityResult在启动另一个activity的时候马上回调
该问题是由于被启动的activity的launchMode为singleTask模式,该模式下不可以使用onActivityResult,要使用onActivityResult,被启动的activit ...
- 【HDOJ6148】Valley Numer(数位DP)
题意: 1≤T≤200 ● 1≤length(N)≤100 思路: 设f[i,j,k,l]为第i位为j,前i位是否贴上限(0/1),递减或递增(0/1)方案数 g[i,j,k]为不到n位,第i位为j, ...
- ci框架(codeigniter)Email发送邮件、收件人、附件、Email调试工具
ci框架(codeigniter)Email发送邮件.收件人.附件.Email调试工具 Email 类 CodeIgniter 拥有强大的 Email 类来提供如下的功能: 多 ...
- 静态区间第k大(分桶法和平方分割)
POJ 2104为例 思想: <挑战程序设计竞赛>中介绍的方法. 分桶法:把一排物品或者平面分成桶,每个桶分别维护自己内部的信息,已达到高效计算的目的. 设一共有n个数,每b个分到一个桶里 ...
- [bzoj4281][ONTAK2015]Związek Harcerstwa Bajtockiego_倍增LCA
Związek Harcerstwa Bajtockiego bzoj-4281 ONTAK-2015 题目大意:给定一棵有n个点的无根树,相邻的点之间的距离为1,一开始你位于m点.之后你将依次收到k ...
- [bzoj4712]洪水_动态dp
洪水 bzoj-4712 题目大意:给定一棵$n$个节点的有根树.每次询问以一棵节点为根的子树内,选取一些节点使得这个被询问的节点包含的叶子节点都有一个父亲被选中,求最小权值.支持单点修改. 注释:$ ...
- iis站点内存泄漏问题分析
在一次上线过程中iis内存飙升,随后跟运维要到站点的dump文件,使用windbg分析了clr的内存分配,找到了问题的症结,先记录如下: 使用windbg加载dump文件 1.打开windbg,Fil ...