zoukankan      html  css  js  c++  java
  • [bzoj1023][SHOI2008]cactus仙人掌图

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    给定一个仙人掌,求最大的两点最短距离。  n<=50000

    好难啊根本不会做。

    题解:先强行dfs把图拆成树,然后我们用f[i]表示i的子树中以i为起点的最长链长度。

    图中的每条边不是桥就是环上的边,对于一座桥,我们先更新一下答案,然后有f[i]=max(f[i],f[j]+1);

    对于一个环,我们只在深度最低的点处理,用环上所有点的f值更新它的f。然后我们考虑最优解在环上的情况,这时我们把环拆链,然后复制一条接起来,在这上面有ans=max(f[i]+f[j]+dis(i,j))。

    假设一条链标号1,2...tot...2tot,我们枚举i,这时候dis(i,j)=i-j,j比k优当且仅当f[i]+f[j]+i-j>f[i]+f[k]+i-k,也就是f[j]-j>f[k]-k,又因为我们在环上,所以长度不能超过tot/2,这个用一个单调队列维护就行了。

    顺便,判断桥的方法是low[j]>dfn[i],即j不能翻到i或之上的点,无向图判环要忽略到父亲的边。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MN 50000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int q[MN+5],dn=0,tot=0,a[2*MN+5],fa[MN+5],top,tail;
    int head[MN+5],n,cnt=0,m,k,f[MN+5],ans=0,dfn[MN+5],low[MN+5];
    struct edge{int to,next;}e[MN*10+5];
    
    void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    
    void dp(int rt,int last)
    {
        for(tot=0;last!=rt;last=fa[last]) a[++tot]=f[last];
        a[++tot]=f[rt];
        for(int i=1;i<=tot;i++)a[i+tot]=a[i];
        q[top=tail=1]=1;
        for(int i=2;i<=tot<<1;i++)
        {
            while(i-q[tail]>tot/2) tail++;
            ans=max(ans,a[i]+a[q[tail]]+i-q[tail]);
            while(top>=tail&&a[i]-i>=a[q[top]]-q[top]) --top;
            q[++top]=i;
        }
        for(int i=1;i<=tot;i++) f[rt]=max(f[rt],a[i]+min(tot-i,i));
    } 
    
    void tarjan(int x,int fat)
    {
        low[x]=dfn[x]=++dn;fa[x]=fat;
        for(int i=head[x];i;i=e[i].next)
        {
            if(!dfn[e[i].to]) tarjan(e[i].to,x),low[x]=min(low[x],low[e[i].to]);
            else if(e[i].to!=fat) low[x]=min(low[x],dfn[e[i].to]);
            if(e[i].to!=fat&&dfn[x]<low[e[i].to]) ans=max(ans,f[x]+f[e[i].to]+1),f[x]=max(f[x],f[e[i].to]+1);
        }
        for(int i=head[x];i;i=e[i].next)
            if(fa[e[i].to]!=x&&dfn[e[i].to]>dfn[x])
                dp(x,e[i].to);
    }
    
    int main()
    {
        n=read();k=read();
        for(int i=1;i<=k;i++)
        {
            int m=read(),pre=read();
            for(int j=2;j<=m;j++)
            {
                int x=read();
                ins(x,pre);pre=x;
            }
        }
        tarjan(1,0);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    链表--判断一个链表是否为回文结构
    矩阵--“之”字形打印矩阵
    二叉树——平衡二叉树,二叉搜索树,完全二叉树
    链表--反转单向和双向链表
    codeforces 490C. Hacking Cypher 解题报告
    codeforces 490B.Queue 解题报告
    BestCoder19 1001.Alexandra and Prime Numbers(hdu 5108) 解题报告
    codeforces 488A. Giga Tower 解题报告
    codeforces 489C.Given Length and Sum of Digits... 解题报告
    codeforces 489B. BerSU Ball 解题报告
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1023.html
Copyright © 2011-2022 走看看