本质上还是树形dp。建立圆方树,遇到圆点的时候直接求(和树形dp一样即可),遇到方点做中转点的时候要考虑会从圆的另一侧通过(需满足最短路径的原则)。原本是对于圆上的点进行 \(n^{2}\) 的匹配,果断超时。但没有发现 \(n ^ {2}\) 的dp明显是一个可以单调队列优化的dp。所以在遇上难解决的问题的时候,一定要融会贯通地思考。有一个细节:将圆复制一下可以去掉 \(max\)造成的影响,dp就十分方便了。

#include <bits/stdc++.h>
using namespace std;
#define maxn 500000
int n, m, N, timer, ans;
int fa[maxn], dfn[maxn], low[maxn];
int f[maxn][], id[maxn], S[maxn];
int tmp[maxn], q[maxn];
int F[maxn][], SS[maxn]; struct edge
{
int cnp, head[maxn], to[maxn], last[maxn], w[maxn];
edge() { cnp = ; }
void add(int u, int v, int ww)
{
to[cnp] = v, last[cnp] = head[u], w[cnp] = ww, head[u] = cnp ++;
to[cnp] = u, last[cnp] = head[v], w[cnp] = ww, head[v] = cnp ++;
}
}E1, E2; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void Solve(int u, int v)
{
++ N; int ID = , pre = ;
for(int i = v; i != fa[u]; i = fa[i])
S[i] = pre ++, id[i] = ++ ID;
S[N] = S[u], S[u] = ;
for(int i = v; i != fa[u]; i = fa[i])
E2.add(N, i, min(S[i], S[N] - S[i]));
} void Tarjan(int u)
{
dfn[u] = low[u] = ++ timer;
for(int i = E1.head[u]; i; i = E1.last[i])
{
int v = E1.to[i];
if(v == fa[u]) continue;
if(!dfn[v])
{
fa[v] = u; Tarjan(v);
low[u] = min(low[u], low[v]);
}
else low[u] = min(low[u], dfn[v]);
if(low[v] > dfn[u]) E2.add(u, v, );
}
for(int i = E1.head[u]; i; i = E1.last[i])
{
int v = E1.to[i];
if(dfn[u] < dfn[v] && fa[v] != u) Solve(u, v);
}
} void update(int u, int w)
{
if(w <= f[u][]) return;
if(w < f[u][]) f[u][] = w;
else f[u][] = f[u][], f[u][] = w;
} bool cmp(int a, int b) { return id[a] < id[b]; } int Work(int u)
{
int head = , tail = , cnt = , ans = , len = ;
for(int i = E2.head[u]; i; i = E2.last[i])
tmp[++ cnt] = f[E2.to[i]][], len ++;
for(int i = ; i <= len; ++ i)
tmp[++ cnt] = tmp[i];
q[head] = ;
for(int i = ; i <= cnt; ++ i)
{
while(head < tail && i - q[head] > len / ) ++ head;
ans = max(ans, tmp[i] + tmp[q[head]] + i - q[head]);
while(head <= tail && tmp[i] - i > tmp[q[tail]] - q[tail] ) -- tail;
q[++ tail] = i;
}
return ans;
} void dfs(int u, int ff)
{
for(int i = E2.head[u]; i; i = E2.last[i])
{
int v = E2.to[i];
if(v == ff) continue; else dfs(v, u);
update(u, f[v][] + E2.w[i]);
}
if(u <= n) ans = max(ans, f[u][] + f[u][]);
else ans = max(ans, Work(u));
} int main()
{
N = n = read(), m = read();
for(int i = ; i <= m; i ++)
{
int tot = read(), u, pre;
for(int j = ; j <= tot; j ++)
{
u = read(); if(j == ) { pre = u; continue; }
E1.add(u, pre, ); pre = u;
}
}
Tarjan();
dfs(, );
printf("%d\n", ans);
return ;
}

【题解】SHOI2008仙人掌图的更多相关文章

  1. [SHOI2008]仙人掌图

    [SHOI2008]仙人掌图 LG传送门 还不会仙人掌的同学可以看看我对仙人掌知识的一些梳理. 题意就是求仙人掌的直径,直径定义为图中最短路径最长的两点间的最短路径长度. 按照套路,先考虑求树的直径我 ...

  2. 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告

    P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...

  3. BZOJ1023:[SHOI2008]仙人掌图——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1023 Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple ...

  4. SHOI2008仙人掌图(tarjan+dp)

    Solution 好题啊没的说. 本题需要求出仙人掌的直径,但仙人掌是一个带有简单环的一张图无法直接用树形dp求解,但它有一个好东西就是没有类似环套环的东西,所以我们在处理时就方便了一些. 思路:ta ...

  5. [SHOI2008]仙人掌图 II——树形dp与环形处理

    题意: 给定一个仙人掌,边权为1 距离定义为两个点之间的最短路径 直径定义为距离最远的两个点的距离 求仙人掌直径 题解: 类比树形dp求直径. f[i]表示i向下最多多长 处理链的话,直接dp即可. ...

  6. BZOJ1023 SHOI2008 仙人掌图 仙人掌、单调队列

    传送门 求仙人掌的直径,可以由求树的直径进行拓展,只需要在环上特殊判断. 沿用求树的直径的DP,对于一条不在任何环内的边,直接像树的直径一样转移,然后考虑环的影响. 设环长为\(cir\),在\(df ...

  7. Luogu 4244 [SHOI2008]仙人掌图

    BZOJ 1023 如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径. 设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f ...

  8. P4244 [SHOI2008]仙人掌图 II

    传送门 仙人掌直径,以前好像模拟赛的时候做到过一道基环树的直径,打了个很麻烦的然而还错了--今天才发现那就是这个的弱化版啊-- 如果是树的话用普通的dp即可,记\(f[u]\)表示\(u\)往下最长能 ...

  9. 洛谷P4244 [SHOI2008]仙人掌图 II

    传送门 首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径. 那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并 ...

随机推荐

  1. js继承的几种方法和es6继承方法

        一.原型链继     1.基本思想     利用原型链来实现继承,超类的一个实例作为子类的原型     2.具体实现     function F() {}     //原型属性,原型方法: ...

  2. 阅读《大型网站技术架构》,并结合"重大需求征集系统"有感

    今天阅读了<大型网站技术架构:核心原理与案例分析>的第五.六.七章.这三张主要是讲述了一个系统的可用性.伸缩性和可扩展性.而根据文中所讲述的,一个系统的可用性主要是体现在这个系统的系统服务 ...

  3. 数据分析处理库Pandas——字符串操作

    字符串小写 字符串大写 字符串长度 去掉字符串中的空格 去掉字符串中的左空格 去掉字符串中的右空格 字符串替换 按字符串切割 字符串是否包含在另一个字符串中

  4. 如何防御网站被ddos攻击 首先要了解什么是流量攻击

    什么是DDOS流量攻击?我们大多数人第一眼看到这个DDOS就觉得是英文的,有点难度,毕竟是国外的,其实简单通俗来讲,DDOS攻击是利用带宽的流量来攻击服务器以及网站. 举个例子,服务器目前带宽是100 ...

  5. 批量安装Python第三方库

    1.首先在python程序的文件夹内,新建一个文本文档,名字自定义,在文档中输入需要安装的第三方库,并用英文半角逗号隔开. import os def getTxt(): txt = open(&qu ...

  6. POJ2186 强连通分量+缩点

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 40234   Accepted: 16388 De ...

  7. 2-Linux C语言指针与内存-学习笔记

    Linux C语言指针与内存 前面我们对于: c语言的基本用法 makeFile文件的使用 main函数的详解 标准输入输出流以及错误流管道 工具与原理 指针与内存都是c语言中的要点与难点 指针 数组 ...

  8. R语言学习笔记(一):mode, class, typeof的区别

    要了解这三个函数的区别,先了解numeric, double与integer. 在r中浮点数有两个名字叫numeric与double. double是指它的类型(type)名字,numeric是指它的 ...

  9. 如何保证HashMap线程安全

    可使用Java 1.5推荐的java.util.concurrent包ConcurrentHashMap来实现,内部不再使用类似HashTable的synchronized同步锁,而是使用Reentr ...

  10. Java-Swing中使用Web富文本编辑器

    资料下载 (截取出了邮件发送的功能.) 2018/11/10 因为要 win7 电脑 IE 8 的原因,使用了 jxBrower 拓展,更容易使用,参考链接(推荐) 问题介绍 window客户端软件的 ...