【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1023

【题意】

【题解】



如果不考虑有环的情况;

那么有一个经典的求树的直径的方法;

首先;

树的直径的两端的端点必然都在树的叶子上(或在根节点,考虑一条链的情况);



设f[i][0]表示离i这个点最远的叶子节点的距离

f[i][1]表示离i这个点第二远的叶子节点的距离

更新的话

f[x][0]=max(f[son][0]+1);

f[x][1] = max(second(f[son][0])+1);

则可以通过dp求出来所有的节点的f值,取max{f[i][0]+f[i][1]}就是它的直径了;

这里我们可以降成一维的即

ans = max(ans,f[x]+f[son]+1),f[x]=max(f[son]+1);

这里f[x]=max(f[son]+1)在ans更新完后才更新;

这个做法就等同于上面那个做法;

然后该题的情况就是多了一个环;

环的话只要通过环上的非最高点对(x,y);

用f(x)+f(y)+dist(x,y)来更新答案ans;

设环上的最高点为u;

然后用非最高点x的f[x]+dist(x,u)来更新f[x]即可;

挺自然的一个做法吧;

这里的

f(x)+f(y)+dist(x,y)

可以写成

f[x]+f[y]+x-y

这里的x和y是把环破成直线之后x和y在直线上的下标;

x>y

则我们只要维护f[y]-y不下降就可以了

用单调队列搞;

然后因为是最短距离;

所以f[y]-y必须要满足x-y< n/2

这里的n是这个环的长度;

也因为是最短距离;

所以你要把直线的长度延伸到2*n,不然可能会漏解.



【完整代码】

#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x)
#define ref(x) scanf("%lf",&x) typedef pair<int, int> pii;
typedef pair<LL, LL> pll; const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
const double pi = acos(-1.0);
const int N = 5e4+100; int n, m,k,a[N*2],dfn[N],low[N],num,father[N],f[N],dep[N],ans,q[2*N];
vector <int> g[N]; void input_data()
{
rei(n), rei(m);
rep1(i, 1, m)
{
rei(k);
rep1(j, 1, k)
rei(a[j]);
rep1(j, 1, k - 1)
g[a[j]].push_back(a[j + 1]), g[a[j + 1]].push_back(a[j]);
}
} void dp(int root, int x)
{
int n = dep[x] - dep[root] + 1;
for (int i = x; i != root; i = father[i])
a[n--] = f[i];
a[n] = f[root], n = dep[x] - dep[root] + 1;
rep1(i, n + 1, 2 * n)
a[i] = a[i - n];
int h = 1, t = 1;
q[h] = 1;
rep1(i, 2, n + n / 2)
{
while (h <= t && i - q[h] > n / 2) h++;
ans = max(ans, a[i] + a[q[h]] + i - q[h]);
while (h <= t && a[q[h]] - q[h] <= a[i] - i) t--;
q[++t] = i;
}
rep1(i, 2, n)
f[root] = max(f[root], a[i] + min(i - 1, n - i + 1));
} void Tarjan(int x)
{
dfn[x] = low[x] = ++num;
int len = g[x].size();
rep1(i, 0, len - 1)
{
int y = g[x][i];
if (y == father[x]) continue;
if (dfn[y] == 0) dep[y] = dep[x] + 1, father[y] = x, Tarjan(y);
low[x] = min(low[x], low[y]);
if (dfn[x] < low[y])
ans = max(ans, f[x] + f[y] + 1), f[x] = max(f[x], f[y] + 1);
}
rep1(i, 0, len - 1)
{
int y = g[x][i];
if (y!=father[x] && father[y] != x && dfn[x] < dfn[y])
dp(x, y);
}
} int main()
{
//freopen("F:\\rush.txt", "r", stdin);
input_data();
Tarjan(1);
printf("%d\n", ans);
//printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}

【BZOJ 1023】[SHOI2008]cactus仙人掌图的更多相关文章

  1. bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan缩环&&环上单调队列

    1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1141  Solved: 435[Submit][ ...

  2. 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图

    Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的 ...

  3. BZOJ 1023: [SHOI2008]cactus仙人掌图 | 在仙人掌上跑DP

    题目: 求仙人掌直径 http://www.lydsy.com/JudgeOnline/problem.php?id=1023 题解: 首先给出仙人掌的定义:满足所有的边至多在一个环上的无向联通图 我 ...

  4. bzoj 1023: [SHOI2008]cactus仙人掌图 2125: 最短路 4728: 挪威的森林 静态仙人掌上路径长度的维护系列

    %%% http://immortalco.blog.uoj.ac/blog/1955 一个通用的写法是建树,对每个环建一个新点,去掉环上的边,原先环上每个点到新点连边,边权为点到环根的最短/长路长度 ...

  5. bzoj 1023 [SHOI2008]cactus仙人掌图 ( poj 3567 Cactus Reloaded )——仙人掌直径模板

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1023 http://poj.org/problem?id=3567 因为lyd在讲课,所以有 ...

  6. bzoj 1023: [SHOI2008]cactus仙人掌图

    这道题是我做的第一道仙人掌DP,小小纪念一下…… 仙人掌DP就是环上的点环状DP,树上的点树上DP.就是说,做一遍DFS,DFS的过程中处理出环,环上的点先不DP,先把这些换上的点的后继点都处理出来, ...

  7. BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)

    题目链接 类似求树的直径,可以用(类似)树形DP求每个点其子树(在仙人掌上就是诱导子图)最长链.次长链,用每个点子节点不同子树的 max{最长链}+max{次长链} 更新答案.(不需要存次长链,求解过 ...

  8. bzoj 1023: [SHOI2008]cactus仙人掌图【tarjan+dp+单调队列】

    本来想先求出点双再一个一个处理结果写了很长发现太麻烦 设f[u]为u点向下的最长链 就是再tarjan的过程中,先照常处理,用最长儿子链和次长儿子链更新按ans,然后处理以这个点为根的环,也就是这个点 ...

  9. 1023: [SHOI2008]cactus仙人掌图 - BZOJ

    Description如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路 ...

  10. 【BZOJ】1023: [SHOI2008]cactus仙人掌图 静态仙人掌(DFS树)

    [题意]给定仙人掌图(每条边至多在一个简单环上),求直径(最长的点对最短路径).n<=50000,m<=10^7. [算法]DFS树处理仙人掌 [题解]参考:仙人掌相关问题的处理方法(未完 ...

随机推荐

  1. C++ 多线程阻塞 (多线程同步)(MsgWaitForMultipleObjects)(连着消息一起控制,牛)

    在主线程定要禁止使用waitforsingleobject(),原因是会阻塞主线程的消息循环,所以必须使用另一种 MsgWaitForMultipleObjects,即可以让消息通过,下面就是一个基于 ...

  2. 【AtCoder Beginner Contest 074 B】Collecting Balls (Easy Version)

    [链接]h在这里写链接 [题意] 看懂题目之后就会发现是道大水题. [题解] 在这里写题解 [错的次数] 0 [反思] 在这了写反思 [代码] #include <bits/stdc++.h&g ...

  3. 第一个hello word 驱动载入失败--------

    今天尝试自己载入第一个驱动模块,依据惯例hello word 然后失败了,如今说明我的操作过程.请个位看看. 首先我的内核版本号: 模块代码与MAKEFILE #include<linux/in ...

  4. PHP与Linux进程间的通信

    进程间通信预计是公司考察应届毕业生的必考点(嵌入式行业).当然非常多公司考的是算法. 不查阅资料,我脑子里能想到的 [1] 管道, (有名.无名) [2] 父子进程 [3] System V (消息队 ...

  5. js闭包(函数内部嵌套一个匿名函数:这个匿名函数可将所在函数的局部变量常驻内存)

    js闭包(函数内部嵌套一个匿名函数:这个匿名函数可将所在函数的局部变量常驻内存) 一.总结 1.闭包:就是在一个函数内部嵌套一个匿名函数,这个匿名函数可以访问这个函数的变量. 二.要点 闭包 闭包的相 ...

  6. C语言主要做哪些方面的开发---一个来自“IT技术学习”微信群的问题及答复

    近期,在"IT技术学习"微信群中,有同学问了这样一个问题:C语言主要做哪些方面的开发?在这篇文章中,我想结合自身的经验,对这个问题进行下解答. C语言是计算机及其相关专业(如通信. ...

  7. Codeforces Round #Pi (Div. 2) B Berland National Library

    B. Berland National Library time limit per test1 second memory limit per test256 megabytes inputstan ...

  8. Dll的链接使用细节

    关于Dll Dll.Exe 都是PE格式的二进制文件. Dll相当于Linux操作系统下的so文件 1 基地址(Base Address)和相对地址(RelativeVirtual Address) ...

  9. thinkphp3.1课程 1-1 为什么thinkphp在开发好后需要关掉开发模式

    thinkphp3.1课程 1-1 为什么thinkphp在开发好后需要关掉开发模式 一.总结 一句话总结:因为调试模式中会记录你所有的调试信息,比如a调用b,b调用c,c调用d,比如你从哪个数据库取 ...

  10. html中radio、checkbox选中状态研究(静下心来看,静下心来总结)

    html中radio.checkbox选中状态研究(静下心来看,静下心来总结) 一.总结 1.单选框的如果有多个checked 会以最后一个为准 2.js动态添加checked属性:不行:通过 $(& ...