题目链接

https://www.luogu.org/problem/P4381

题解

基环树直径的板子。但是dfs会爆栈...所以最后改成了bfs。还是一个很考验码力的板子。

首先基环树的直径显然有两种情况,在不进入环的情况下在一个子树内,这直接dp求就好了。第二种是一个子树中的链+环上一段+另外一个子树中的链。按这两种情况分类讨论即可。对于这种情况,可以在先求第一种情况的同时把子树中的以子树的根为起点的最长链求出来,然后拓扑排序找出环,处理出环上的前缀和,断环成链,在上面跑一下单调队列就可以求出第二种情况下的\(\max\)了。然后这道题里这些步骤最好都是用bfs实现,dfs可能会爆栈...各种细节也要注意好...复杂度是\(O(n)\)的。

#include <bits/stdc++.h>
using namespace std; namespace io {
char buf[1<<21], *p1 = buf, *p2 = buf;
inline char gc() {
if(p1 != p2) return *p1++;
p1 = buf;
p2 = p1 + fread(buf, 1, 1 << 21, stdin);
return p1 == p2 ? EOF : *p1++;
}
#define G gc #ifndef ONLINE_JUDGE
#undef G
#define G getchar
#endif template<class I>
inline void read(I &x) {
x = 0; I f = 1; char c = G();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = G(); }
x *= f;
}
template<class I>
inline void write(I x) {
if(x == 0) {putchar('0'); return;}
I tmp = x > 0 ? x : -x;
if(x < 0) putchar('-');
int cnt = 0;
while(tmp > 0) {
buf[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while(cnt > 0) putchar(buf[--cnt]);
} #define in(x) read(x)
#define outn(x) write(x), putchar('\n')
#define out(x) write(x), putchar(' ') } using namespace io; #define ll long long
const int N = 1000100; deque<int>q;
int n, b[N], tot, in[N];
int head[N], cnt = 1, vis[N * 2];
int Ctot, c[N], a[N * 2];
struct edge {
int to, nxt;
int v;
} e[N << 1];
ll ans = 0, now = 0, s[N * 2], f[N * 2], d[N]; void ins(int u, int v, int w) {
e[++cnt] = (edge) {v, head[u], w};
head[u] = cnt;
} void bfs(int S, int bl) {
c[S] = bl;
q.clear(); q.push_back(S);
while(!q.empty()) {
int u = q.front(); q.pop_front();
c[u] = bl;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(!c[v]) q.push_back(v);
}
}
} void topsort() {
q.clear();
for(int i = 1; i <= n; ++i) {
if(in[i] == 1) q.push_back(i);
}
while(!q.empty()) {
int u = q.front(); q.pop_front();
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(in[v] > 1) {
d[c[u]] = max(d[c[u]], f[u] + f[v] + e[i].v);
f[v] = max(f[v], f[u] + e[i].v);
--in[v]; if(in[v] == 1) q.push_back(v);
}
}
}
} void dp(int S, int vc) {
int tot = 0, u = S;
a[++tot] = u;
while(1) {
bool flag = 0;
in[u] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(in[v] > 1) {a[++tot] = v; s[tot] = s[tot - 1] + e[i].v; u = v; flag = 1; break;}
}
if(!flag) break;
}
if(tot == 2) {
int val = 0;
for(int i = head[S]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == a[2]) val = max(val, e[i].v);
}
d[vc] = max(d[vc], f[a[1]] + f[a[2]] + val);
return;
}
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == S) {a[++tot] = S; s[tot] = s[tot - 1] + e[i].v; break;}
}
for(int i = tot + 1; i <= (tot - 1) * 2; ++i) {
a[i] = a[i - tot + 1];
s[i] = s[i - 1] + s[i - tot + 1] - s[i - tot];
}
q.clear(); q.push_back(1);
ll sum = 0;
for(int i = 2; i <= (tot - 1) * 2; ++i) {
while(!q.empty() && i - q.front() + 1 > (tot - 1)) q.pop_front();
sum = max(sum, f[a[q.front()]] + f[a[i]] + s[i] - s[q.front()]);
while(!q.empty() && f[a[i]] - s[i] > f[a[q.back()]] - s[q.back()]) q.pop_back();
q.push_back(i);
}
d[vc] = max(d[vc], sum);
} int main() {
read(n);
for(int x, i = 1; i <= n; ++i) {
ll w; read(x); read(w);
ins(i, x, w), ins(x, i, w);
in[i]++; in[x]++;
}
for(int i = 1; i <= n; ++i) {
if(!c[i]) bfs(i, ++Ctot);
}
topsort();
for(int i = 1; i <= n; ++i) {
if(!vis[c[i]] && in[i] > 1) {
vis[c[i]] = 1;
dp(i, c[i]);
ans += d[c[i]];
}
}
outn(ans);
}

LGOJP4381 [IOI2008]Island的更多相关文章

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

    1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1826  Solved: 405[Submit][S ...

  2. IOI2008 island

    题目链接:[IOI2008]Island 题目大意:求基环树直径(由于题目的意思其实是类似于每个点只有一个出度,所以在每个联通块中点数和边数应该是相同的,这就是一棵基环树,所以题目给出的图就是一个基环 ...

  3. P4381 [IOI2008]Island(基环树+单调队列优化dp)

    P4381 [IOI2008]Island 题意:求图中所有基环树的直径和 我们对每棵基环树分别计算答案. 首先我们先bfs找环(dfs易爆栈) 蓝后我们处理直径 直径不在环上,就在环上某点的子树上 ...

  4. bzoj千题计划114:bzoj1791: [Ioi2008]Island 岛屿

    http://www.lydsy.com/JudgeOnline/problem.php?id=1791 就是求所有基环树的直径之和 加手工栈 #include<cstdio> #incl ...

  5. BZOJ1791: [Ioi2008]Island 岛屿

    BZOJ1791: [Ioi2008]Island 岛屿 Description 你将要游览一个有N个岛屿的公园. 从每一个岛i出发,只建造一座桥. 桥的长度以Li表示. 公园内总共有N座桥. 尽管每 ...

  6. [题解] LuoguP4381 [IOI2008]Island

    LuoguP4381 [IOI2008]Island Description 一句话题意:给一个基环树森林,求每棵基环树的直径长度的和(基环树的直径定义与树类似,即基环树上一条最长的简单路径),节点总 ...

  7. [bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)

    [bzoj1791][ioi2008]Island 岛屿(基环树.树的直径) bzoj luogu 题意可能会很绕 一句话:基环树的直径. 求直径: 对于环上每一个点记录其向它的子树最长路径为$dp_ ...

  8. bzoj 1791: [Ioi2008]Island 岛屿

    #include<iostream> #include<cstdio> #define M 1000009 using namespace std; *M],cnt,n,hea ...

  9. 【BZOJ 1791】 [Ioi2008]Island 岛屿

    Description 你将要游览一个有N个岛屿的公园.从每一个岛i出发,只建造一座桥.桥的长度以Li表示.公园内总共有N座桥.尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走.同时,每一对这样 ...

随机推荐

  1. SpringBoot系列教程JPA之delete使用姿势详解

    原文: 190702-SpringBoot系列教程JPA之delete使用姿势详解 常见db中的四个操作curd,前面的几篇博文分别介绍了insert,update,接下来我们看下delete的使用姿 ...

  2. python 可变数据类型和不可变数据类型(7)

    python数据类型分别有整数int / 浮点数float / 布尔值bool / 元组tuple / 列表list / 字典dict,其中数据类型分为两个大类,一种是可变数据类型:一种是不可变数据类 ...

  3. Linux06 文件的打包和压缩(gzip/gunzip、tar、bzip2)

    一.gzip/gunzip 这是用于压缩和解压单个文件的工具,且使用方法比较简单 gzip  文件名 gunzip  文件名 二.tar(用的比较多) 不仅可以用于打包文件,还可以将整个目录中的全部文 ...

  4. 20190715《Python网络数据采集》第 1 章

    <Python网络数据采集>7月8号-7月10号,这三天将该书精读一遍,脑海中有了一个爬虫大体框架后,对于后续学习将更加有全局感. 此前,曾试验看视频学习,但是一个视频基本2小时,全部拿下 ...

  5. 20191213-RF中报告打不开提示Opening Robot Framework report failed

    配置好Jenkins的RF框架后跑了一次autotest发现哦豁report打不开,网上找了一堆方法都是只能临时解决,重启后又失效了.现在给出临时解决方案和永久解决方案 首先错误信息如下:  临时解决 ...

  6. 05- if-else语句、循环for

    if-else 语句 if是条件语句.if语句的语法是 if 条件{ #注意大括号和条件之间不能换行 执行代码 } if语句还包括else if 和 else 部分 package main impo ...

  7. PAT(B) 1065 单身狗(Java:17分,C:25分)

    题目链接:1065 单身狗 (25 point(s)) 题目描述 "单身狗"是中文对于单身人士的一种爱称.本题请你从上万人的大型派对中找出落单的客人,以便给予特殊关爱. 输入格式 ...

  8. 【IDEA使用技巧】(4) —— IDEA 构建Java Maven项目、导入Eclipse项目、多Module Maven项目

    1.IntelliJ IDEA构建Java Maven项目 1.1. IDEA构建Java Maven项目 ①选择Create New Project,选择创建Maven项目,并勾选Create fr ...

  9. Jenkins + GitLab + SpringBoot 实现持续集成脚本

    Linux脚本 #!/bin/bash jar_name=hq-api.jar cd /usr/local/app/hq-api echo "Stopping SpringBoot Appl ...

  10. JXOI2018

    发现自己不会T3可以退群了 排序问题(组合.模拟) 可以发现Gobo Sort相当于在所有排列中随机选择一个,所以当第\(i\)个数出现次数为\(a_i\)时,期望的Sort次数就是\(\frac{( ...