BZOJ1023 SHOI2008 仙人掌图 仙人掌、单调队列
求仙人掌的直径,可以由求树的直径进行拓展,只需要在环上特殊判断。
沿用求树的直径的DP,对于一条不在任何环内的边,直接像树的直径一样转移,然后考虑环的影响。
设环长为\(cir\),在\(dfs\)树上,环对应的链的链顶为\(top\),链底为\(bot\),也就是说返祖边为\((top,bot)\),点\(x\)在\(dfs\)树上的深度为\(dep_x\)。
在统计环上的点之间的转移和贡献之前,先把环上所有点的子仙人掌的贡献统计好。
环上的转移直接通过方程式\(dp_{top} \leftarrow dp_{u} + \min\{dep_u - dep_{top} , cir - dep_u + dep_{top}\}\)从所有点转移到链顶
考虑如何统计环上的贡献,相对来说是比较难的一部分。
对于在环上的两个点\(u,v(dep_u > dep_v)\),它们对答案的贡献为\(dp_u + dp_v + \min\{dep_u - dep_{v} , cir - dep_u + dep_{v}\}\)
我们考虑将\(dp_u +dp_v + dep_u - dep_v\)和\(dp_u + dp_v + cir + dep_v - dep_u\)的贡献分开计算。下面只说\(dp_u + dp_v + dep_u - dep_v\)的情况,另一种计算同理。
我们考虑按照深度从大往小加点,那么如果对于两个点\(i,j\)满足\(dep_i < dep_j \&\& dep_i + dp_i \geq dep_j + dp_j\),表示\(i\)相比于\(j\)能够对更多的点产生贡献,而且转移更优,那么\(j\)就是没有必要的了。可以发现转移满足单调队列优化的性质,使用单调队列优化转移即可。记得转移需要满足\(dep_u - dep_v < cir + dep_v - dep_u\),如果队首不满足这个条件需要删除。
#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == '-')
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
}
const int MAXN = 1e5 + 10;
struct Edge{
int end , upEd;
}Ed[MAXN << 2];
int head[MAXN] , dp[MAXN] , dep[MAXN] , fa[MAXN] , ch[MAXN];
int N , M , cntEd , ans;
deque < int > q;
inline void addEd(int a , int b){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
}
void calc(int top , int bot){
int cir = dep[bot] - dep[top] + 1 , p = bot;
q.push_back(bot);
do{
ch[fa[p]] = p;
p = fa[p];
int t = q.front();
if(dep[t] - dep[p] > cir - dep[t] + dep[p]){
q.pop_front();
t = q.front();
}
ans = max(ans , dep[t] - dep[p] + dp[t] + dp[p]);
while(!q.empty() && dep[q.back()] + dp[q.back()] <= dep[p] + dp[p])
q.pop_back();
q.push_back(p);
}while(p != top);
q.clear();
int p1 = top;
p = bot;
q.push_back(p1);
while(cir - dep[p] + dep[top] <= dep[p] - dep[top])
p = fa[p];
do{
p1 = ch[p1];
p = ch[p];
int t = q.front();
ans = max(ans , cir + dep[t] - dep[p] + dp[t] + dp[p]);
while(!q.empty() && dep[q.back()] + dp[q.back()] <= dep[p1] + dp[p1])
q.pop_back();
q.push_back(p1);
}while(p != bot);
q.clear();
p = bot;
while(p != top){
dp[top] = max(dp[top] , dp[p] + min(dep[p] - dep[top] , cir + dep[top] - dep[p]));
p = fa[p];
}
}
int dfs(int x , int p){
fa[x] = p;
dep[x] = dep[p] + 1;
int t = 0;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != p)
if(dep[Ed[i].end])
if(dep[Ed[i].end] < dep[x])
t = Ed[i].end;
else
calc(x , Ed[i].end);
else{
int q = dfs(Ed[i].end , x);
if(!q){
ans = max(ans , dp[x] + dp[Ed[i].end] + 1);
dp[x] = max(dp[x] , dp[Ed[i].end] + 1);
}
else
if(q != x)
t = q;
}
return t;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
N = read();
M = read();
for(int i = 1 ; i <= M ; ++i){
int L = read() , a = read();
for(int i = 2 ; i <= L ; ++i){
int b = read();
addEd(a , b);
addEd(b , a);
a = b;
}
}
dfs(1 , 0);
cout << ans;
return 0;
}
BZOJ1023 SHOI2008 仙人掌图 仙人掌、单调队列的更多相关文章
- 1023: [SHOI2008]cactus仙人掌图(DP+单调队列优化)
这道题吗= =首先解决了我多年以来对仙人掌图的疑问,原来这种高大上的东西原来是这个啊= = 然后,看到这种题,首先必须的就是缩点= = 缩点完之后呢,变成在树上找最长路了= =直接树形dp了 那么那些 ...
- BZOJ1023: [SHOI2008]cactus仙人掌图(仙人掌dp)
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3467 Solved: 1438[Submit][Status][Discuss] Descripti ...
- BZOJ1023: [SHOI2008]cactus仙人掌图(仙人掌)
Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的 ...
- BZOJ1023:[SHOI2008]cactus仙人掌图(圆方树,DP,单调队列)
Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus). 所谓简单回路就是指在图上不重复经过任何一个顶点 ...
- 2018.10.29 bzoj1023: [SHOI2008]cactus仙人掌图(仙人掌+单调队列优化dp)
传送门 求仙人掌的直径. 感觉不是很难. 分点在环上面和不在环上分类讨论. 不在环上直接树形dpdpdp. 然后如果在环上讨论一波. 首先对环的祖先有贡献的只有环上dfsdfsdfs序最小的点. 对答 ...
- bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan缩环&&环上单调队列
1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1141 Solved: 435[Submit][ ...
- bzoj 1023: [SHOI2008]cactus仙人掌图【tarjan+dp+单调队列】
本来想先求出点双再一个一个处理结果写了很长发现太麻烦 设f[u]为u点向下的最长链 就是再tarjan的过程中,先照常处理,用最长儿子链和次长儿子链更新按ans,然后处理以这个点为根的环,也就是这个点 ...
- bzoj千题计划113:bzoj1023: [SHOI2008]cactus仙人掌图
http://www.lydsy.com/JudgeOnline/problem.php?id=1023 dp[x] 表示以x为端点的最长链 子节点与x不在同一个环上,那就是两条最长半链长度 子节点与 ...
- bzoj1023: [SHOI2008]cactus仙人掌图
学习了一下圆方树. 圆方树是一种可以处理仙人掌的数据结构,具体见这里:http://immortalco.blog.uoj.ac/blog/1955 简单来讲它是这么做的:用tarjan找环,然后对每 ...
随机推荐
- AndroidStudio安装、配置、测试
AndroidStudio安装.配置.测试(win7_64bit) 目录 1.概述 2.本文用到的工具 3.安装测试 4.模拟器安装.使用 5.常用配置 6.注事事项 7.相关博文 >>看 ...
- Tomcat映射虚拟路径到指定磁盘(eclipse)
用WangEditor富文本编辑,上传图片的时候,本文主要记录一下Tomcat映射虚拟路径到指定磁盘,保存到指定路径中,且能实现页面预览. 在实现之前wangeditor的简单实用请参照博主小道仙的后 ...
- Android--小游戏
GitHub:https://github.com/vinieo/game 功能描述 “猜小球”是一个简单的愉悦身心的小游戏,它的功能结构如图a-1所示. 构建开发环境 在开发本游戏时,首先需要下 ...
- SQL SERVER LINUX
以前在Linux平台上访问SQL Server时常用的方式有:http://www.freetds.org/https://sourceforge.net/projects/jtds/这方面的资料已经 ...
- java----堆区、方法区和栈区
堆区:只存放类对象,线程共享: 方法区:又叫静态存储区,存放class文件和静态数据,线程共享; 栈区:存放方法局部变量,基本类型变量区.执行环境上下文.操作指令区,线程不共享; class A { ...
- hive笔记:转义字符的使用
hive中的转义符 Hadoop和Hive都是用UTF-8编码的,所以, 所有中文必须是UTF-8编码, 才能正常使用 备注:中文数据load到表里面, 如果字符集不同,很有可能全是乱码需要做转码的, ...
- Python 提案
学习Java 不可不知JSR,学习Python自然也得知道 PEP了 1- PEP简介 PEP是Python增强提案(Python Enhancement Proposal)的缩写.https://w ...
- 排序算法之直接插入排序的思想以及Java实现
1,基本思想 假设待排序的数据是数组A[1-.n].初始时,A[1]自成1个有序区,无序区为A[2-.n].在排序的过程中,依次将A[i] (i=2,3,-.,n)从后往前插入到前面已排好序的子数组A ...
- 【算法】LeetCode算法题-Longest Common Prefix
这是悦乐书的第146次更新,第148篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第5题(顺位题号是14),给定一个随机的字符串数组,查找这些字符串元素的公共前缀字符串, ...
- June 1. 2018 Week 22nd Friday
What makes life dreary is the want of motive. 没有了目的,生活便暗淡无光. We all have dreams about our future, we ...