传送门

题解

题意 = 找出无向基环树森林的每颗基环树的直径。

我们首先需要找到每颗基环树的环, 但是因为是无向图,用tarjan找环, 加个手工栈, 我也是看了dalao的博客才知道tarjan找无向图环 :

dalao的链接

然鹅大佬的方法有一点小问题, 无法找出只有两个节点的环,改动后代码:

 void dfs(int x, int last) {
dfn[x] = ++sz;
for(int i = head[x]; i; i = e[i].nxt) {
if(i == last ^ ) continue;
int nt = e[i].to;
if(dfn[nt]) {
if(dfn[nt] < dfn[x]) continue;
cur.push_back(x); mk[x] = ;
for(; nt != x; nt = pre[nt]) cur.push_back(nt), mk[nt] = ;
}
else pre[nt] = x, dfs(nt, i);
}
}

加了手工栈后的代码

 int lev2;

 int st_i2[N],st_x2[N],st_y2[N],st_t2[N];

 #define i st_i2[lev2]
#define y st_y2[lev2]
#define x st_x2[lev2]
#define nt st_t2[lev2] void dfs(int u, int last) {
lev2 = ;
st_x2[] = u; st_y2[] = last;
start:;
dfn[x] = ++sz;
for(i = head[x]; i; i = e[i].nxt) {
nt = e[i].to;
if(i == ch(y)) continue;
if(dfn[nt]) {
if(dfn[nt] < dfn[x]) continue;
cur.push_back(x); mk[x] = ;
for(; nt != x; nt = pre[nt]) mk[nt] = , cur.push_back(nt);
continue;
}
pre[nt] = x;
st_x2[lev2 + ] = nt;
st_y2[lev2 + ] = i;
lev2++;
goto start;
end:;
}
lev2--;
if(lev2) goto end;
} #undef i
#undef y
#undef x
#undef nt

设tmp 为某棵基环树的直径

tmp可能是某个环上点的子树的直径, 也有可能是环上两个点之间的距离+两个点到子树的最大距离

找出环后, 求出环上的每个点的子树中的直径, 每颗子树的直径中都更新 tmp的最大值。

接着求出从环上每个点到它子树节点的最远距离$d$, tmp的最大值也可能为 $d_i + d_j + dist(i, j)$。

这个式子最大值可以用拆环+单调队列O(N)求出。

然后把tmp 加到最后答案

代码

为什么不加手工栈比加了手工栈慢20倍

 #include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define rd read()
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define per(i,a,b) for(int i = (a); i >= (b); --i)
#define ll long long
#define R register
using namespace std; const int N = 1e6 + 1e5; int n, head[N], tot, dfn[N], pre[N], sz;
int q[N], mk[N], pos[N];
ll ans, d[N], f[N]; vector<int> pt;
vector<ll> len; struct edge {
int nxt, to, val;
}e[N << ]; int read() {
R int X = , p = ; R char c = getchar();
for(; c > '' || c < ''; c = getchar()) if(c == '-') p = -;
for(; c >= '' && c <= ''; c = getchar()) X = X * + c - '';
return X * p;
} void add(int u, int v, int val) {
e[++tot].to = v;
e[tot].val = val;
e[tot].nxt = head[u];
head[u] = tot;
} int ch(int x) {
return ((x + ) ^ ) - ;
} int lev2; int st_i2[N],st_x2[N],st_y2[N],st_t2[N]; #define i st_i2[lev2]
#define y st_y2[lev2]
#define x st_x2[lev2]
#define nt st_t2[lev2] void dfs(int u, int last) {
lev2 = ;
st_x2[] = u; st_y2[] = last;
start:;
dfn[x] = ++sz;
for(i = head[x]; i; i = e[i].nxt) {
nt = e[i].to;
if(i == ch(y)) continue;
if(dfn[nt]) {
if(dfn[nt] < dfn[x]) continue;
pt.push_back(x); mk[x] = ;
for(; nt != x; nt = pre[nt]) mk[nt] = , pt.push_back(nt);
continue;
}
pre[nt] = x;
st_x2[lev2 + ] = nt;
st_y2[lev2 + ] = i;
lev2++;
goto start;
end:;
}
lev2--;
if(lev2) goto end;
} #undef i
#undef y
#undef x
#undef nt int lev;
int st_x[N], st_y[N], st_i[N], st_t[N]; #define i st_i[lev]
#define x st_x[lev]
#define y st_y[lev]
#define nt st_t[lev] void dfs2(int u, int fa) {
lev = ;
st_x[] = u; st_y[] = fa;
start:;
for(i = head[x]; i; i = e[i].nxt) {
nt = e[i].to;
if(nt == y || mk[nt]) continue;
st_x[lev + ] = nt;
st_y[lev + ] = x;
lev++;
goto start;
end:;
f[x] = max(f[x], f[nt]);
f[x] = max(f[x], d[x] + d[nt] + e[i].val);
d[x] = max(d[x], d[nt] + e[i].val);
}
lev--;
if(lev) goto end;
} #undef i
#undef x
#undef y
#undef nt void work(int x) {
ll tmp = ; int cnt;
pt.clear(); len.clear();
dfs(x, ); cnt = pt.size();
pt.push_back(pt[]);
len.push_back();
for(R int i = ; i < cnt; ++i) {
for(R int k = head[pt[i]]; k; k = e[k].nxt) if(e[k].to == pt[(i + ) % cnt])
len.push_back(e[k].val);
}
for(R int i = ; i < cnt; ++i)
pt.push_back(pt[i]), len.push_back(len[i]); rep(i, , cnt * - ) {
len[i] += len[i - ];
}
rep(i, , cnt - ) dfs2(pt[i], ), tmp = max(tmp, f[pt[i]]);
int l = , r = ;
rep(i, , cnt * - ) {
while(l <= r && i - q[l] >= cnt) l++;
if(l <= r) tmp = max(tmp, d[pt[i]] + d[pt[q[l]]] + len[i] - len[q[l]]);
else tmp = max(tmp, d[pt[i]]);
while(l <= r && d[pt[i]] - len[i] >= d[pt[q[r]]] - len[q[r]]) r--;
q[++r] = i;
}
ans += tmp;
} int main()
{
n = rd;
rep(i, , n) {
int v = rd, val = rd;
add(i, v, val); add(v, i, val);
}
rep(i, , n) if(!dfn[i]) {
work(i);
}
printf("%lld\n", ans);
}

BZOJ 1791: [IOI2008]Island 岛屿 - 基环树的更多相关文章

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

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

  2. bzoj 1791: [Ioi2008]Island 岛屿【基环树+单调队列优化dp】

    我太菜了居然调了一上午-- 这个题就是要求基环树森林的基环树直径和 大概步骤就是找环->dp找每个环点最远能到达距离作为点权->复制一倍环,单调队列dp 找环是可以拓扑的,但是利用性质有更 ...

  3. BZOJ1791 [Ioi2008]Island 岛屿[基环树+单调队列优化DP]

    基环树直径裸题. 首先基环树直径只可能有两种形式:每棵基环树中的环上挂着的树的直径,或者是挂在环上的两个树的最大深度根之间的距离之和. 所以,先对每个连通块跑一遍,把环上的点找出来,然后对环上每个点跑 ...

  4. bzoj 1791: [Ioi2008]Island 岛屿

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

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

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

  6. BZOJ1791[Ioi2008]Island 岛屿 ——基环森林直径和+单调队列优化DP+树形DP

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

  7. [BZOJ1791][IOI2008]Island岛屿(环套树DP)

    同NOI2013快餐店(NOI出原题?),下面代码由于BZOJ栈空间过小会RE. 大致是对每个连通块找到环,在所有内向树做一遍DP,再在环上做两遍前缀和优化的DP. #include<cstdi ...

  8. 【BZOJ1791】【IOI2008】【基环树】island(status第一速度)

      1791: [Ioi2008]Island 岛屿  Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 908  Solved: 159 [Su ...

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

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

随机推荐

  1. window document树

  2. Java多线程及线程状态转换

    以下内容整理自:http://blog.csdn.net/wtyvhreal/article/details/44176369 线程:是指进程中的一个执行流程.  线程与进程的区别:每个进程都需要操作 ...

  3. maven(一)入门

    1.maven 简介:不用手动拷贝jar包,只需要配置坐标,自动从中央仓库下载(其他介绍请百度,这里只讲干货) 2.安装maven 1.解压与配置环境变量 2.验证是否安装成功 3.maven介绍 1 ...

  4. Java中this和super的用法和区别

    super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句). this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句). this的实例: package ...

  5. 媒体类型 & 媒体查询

    [媒体类型 & 媒体查询] @media 规则允许在相同样式表为不同媒体设置不同的样式. 在下面的例子告诉我们浏览器屏幕上显示一个14像素的Verdana字体样式.但是如果页面打印,将是10个 ...

  6. love is ... ...

    16 years old, love is dream.20 years old, love is sex.30 years old, love is marriage. 40 years old, ...

  7. Java Arrays

    最近经常有操作数组的需求,排序,倒转等操作,所以深入了解一下Arrays类 equals(a,b)比较数组a和数组b是否相等 toString(a)输出数组a binarySearch(a,i)二分查 ...

  8. Jmeter:性能测试指南(转)

    http://yukinami.github.io/2015/11/26/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%8C%87%E5%8D%97/ 性能测试指南 ...

  9. Java 面向切面 AOP

    参考: :http://www.blogjava.net/supercrsky/articles/174368.html AOP: Aspect Oriented Programming 即面向切面编 ...

  10. day21 xml模块 ATM+购物车

    1. xml模块 <father name="jack"> # 属性的值必须加双引号 <son> 标签的关闭顺序,与开启顺序相反, 最先开启的最后关闭,最后 ...