P4244 [SHOI2008]仙人掌图 II

P4244 [SHOI2008]仙人掌图 II

仙人掌求直径,和树一样最大+次大
处理环时,算一下环内两点距离+子树最大和,根节点此时的其他子树已确定的最大子树 用 环内一点距离+点最大子树更新

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e7;
inline LL Read(){
    LL x=0,f=1; char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1; c=getchar();
    }
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
struct node{
    LL to,next;
}dis[maxn];
LL n,m,num,ans,tot;
LL dp[maxn],dep[maxn],low[maxn],dfn[maxn],a[maxn],head[maxn],fa[maxn],q[maxn];
inline void Add(LL u,LL v){
    dis[++num]=(node){v,head[u]},head[u]=num;
}
inline void Dp(LL u,LL v){
    LL len=dep[v]-dep[u]+1,j=len;
    for(int i=v;i!=u;i=fa[i])
        a[j--]=dp[i]; a[j]=dp[u];
    for(LL i=1;i<=len;++i)
        a[i+len]=a[i];
    LL hea=1,tail=1;
    q[1]=1;
    for(LL i=2;i<=len*2;++i){
        while(hea<=tail&&i-q[hea]>len/2)
            hea++;
        ans=max(ans,a[i]+i+a[q[hea]]-q[hea]);
        while(hea<=tail&&a[q[tail]]-q[tail]<a[i]-i)
            --tail;
        q[++tail]=i;
    }
    for(LL i=2;i<=len;i++)
        dp[u]=max(dp[u],a[i]+min(i-1,len-i+1));
}
void Tarjan(LL u){
    //printf("%lld\n",u);
    low[u]=dfn[u]=++tot;
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(v==fa[u])
            continue;
        if(!dfn[v]){
            dep[v]=dep[u]+1,
            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]){
            ans=max(ans,dp[u]+dp[v]+1);
            dp[u]=max(dp[u],dp[v]+1);
        }
    }
    for(LL i=head[u];i;i=dis[i].next){
        LL v=dis[i].to;
        if(fa[v]!=u&&dfn[u]<dfn[v])
            Dp(u,v);
    }
}
int main(){
    n=Read(), m=Read();
    while(m--){
        LL kase=Read();
        LL pre=Read();
        for(LL i=2;i<=kase;++i){
            LL now=Read();
            Add(now,pre),Add(pre,now),
            pre=now;
        }
    }
    Tarjan(1);
    printf("%lld",ans);
    return 0;
}/*
15 3
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
5 2 14 9 15 10

8
*/

原文地址:https://www.cnblogs.com/y2823774827y/p/10201005.html

时间: 2024-08-29 10:10:16

P4244 [SHOI2008]仙人掌图 II的相关文章

bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan索环&amp;&amp;环上单调队列

1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1141  Solved: 435[Submit][Status] Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路. 举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路

【BZOJ 1023】 [SHOI2008]cactus仙人掌图

1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 1235  Solved: 482 [Submit][Status] Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路. 举例来说,上面的第一个例子是一张仙人图,而第二个不是--注意到它有三条简单

【BZOJ】【1023】【SHOI2008】cactus仙人掌图

DP/仙人掌 题解:http://hzwer.com/4645.html->http://z55250825.blog.163.com/blog/static/150230809201412793151890/ QAQ了 呃……第一次做仙人掌的题目……感觉性质还是蛮神奇的(我是不是应该先做一点环套树的题目呢?>_>) 每个点都只会在一个简单环上,所以在dfs的时候,对于一个环,它上面的点是深度连续的一段(沿着father可以遍历这个环!),然后最后一个点再指回起始点,所以只要low改变了

bzoj千题计划113:bzoj1023: [SHOI2008]cactus仙人掌图

http://www.lydsy.com/JudgeOnline/problem.php?id=1023 dp[x] 表示以x为端点的最长链 子节点与x不在同一个环上,那就是两条最长半链长度 子节点与x在同一个环上,环形DP,单调队列优化 对于每一个环,深度最小的那个点 有可能会更新 上层节点, 所以 每一个环DP完之后,更新 dp[深度最小的点] #include<cstdio> #include<iostream> #include<algorithm> using

bzoj 1023 仙人掌图

Description 求一个仙人掌图的直径 Solution 仙人掌图有个性质,一条边要么是割边要么就是在环内,那么我们可以对它进行Dp辣! 令f[u]表示以u为根的子树最长链长度 如果u?v是桥的话转移就是ans=max(ans,f[u]+f[v]+1),f[u]=max(f[u],f[v]+1),因为当前f[u]都是由它的孩子更新来的 如果是环的话,变环为链,用单调队列dp出ans,然后用环上的f值更新f[u]的值就可以了,具体实现见代码 Code #include <bits/stdc+

HDU - 3594 Cactus(仙人掌图)

题目大意:给出仙人掌图的定义: 1.必须是强连通 2.每条边只能属于一个环 解题思路:在tarjan算法中加入点东西就可以判断了 只要该点能连到之前的点,那么形成环了,找到这个环的所有的边,并标记 如果有一条边被标记了两次了,那图就不是仙人掌图了 关键是怎么找到这个环的所有边,我们可以引入另一个栈,这个栈存放的是边的序号 假设当前点为u,u点连回之前的点是v,那么就从栈里面找边,找到出发点为v的边为止,找到的这些边都是环上的边,这个和tarjan算法的找同一个连通分量的点的道理是一样 #incl

HDU3594 Cactus ([好题] 强连通之仙人掌图 )

题意:判断是不是仙人掌图,仙人掌图的定义, 1.首先是强连通的 2.任意一个遍只能属于一个圈. 仙人掌图的分析 #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<set> #include<map> #include<string> #include<cstring> #include<stac

UVA 10510 - Cactus(有向仙人掌图判定)

UVA 10510 - Cactus 题目链接 题意:给定一个有向图,问这个图是否为仙人掌图(一条边不属于两个及以上环) 思路:类似构造scc的dfs,判定方法为: 1.必然是一个强连通分量 2.一个环上的节点必然只能经过一次 那么dfs的时候,只要记录下每个结点的父亲结点,如果遇到一个结点之前遍历过了,那么就回退的找到改结点,把环上的结点都+1(注意当前结点不算,因为多个环可以连在一个结点上),然后如果有一个结点超过了2,就肯定不是仙人掌图了 代码: #include <cstdio> #i

图论6——仙人掌图

如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌 图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路. 输入的第一行包括两个整数n和m(1≤n≤50000以及0≤m≤10000).其中n代表顶点个数,我们约定图中的顶点将从1到n编号.接下来一共有m行.代表m条路径.每行的开始有一个整数k(2≤k≤1000),代表在这条路径上的顶点个数.接下来是k个1到n之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两