• [SHOI2008]仙人掌图


    题目链接
    考虑用(tarjan)找环,环内(dp),环外(dp).
    (f[u])表示到(u)点的最长距离长度.
    如果我们找到一条边是桥就直接转移——(f[u]=max(f[u],f[v]+len)),同时更新(Ans).
    我们其实要求的就是(max(f[i]+f[j]+dis(i,j)))
    如果我们找到一个环,首先用环中节点的(f)值去更新(Ans).
    首先破环成链,然后这显然是一个区间(dp).
    我们用单调队列去优化这个(dp)
    如果队首和现在节点的距离大于(frac{Len_{cir}}{2}),就(pop).

    然后把这个环的答案都并到环的起始点即可.
    代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #define N (1000010)
    #define M (20000010)
    #define inf (0x7f7f7f7f)
    #define rg register int
    #define Label puts("NAIVE")
    #define spa print(' ')
    #define ent print('
    ')
    #define rand() (((rand())<<(15))^(rand()))
    typedef long double ld;
    typedef long long LL;
    typedef unsigned long long ull;
    using namespace std;
    inline char read(){
        static const int IN_LEN=1000000;
        static char buf[IN_LEN],*s,*t;
        return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
    }
    template<class T>
    inline void read(T &x){
        static bool iosig;
        static char c;
        for(iosig=false,c=read();!isdigit(c);c=read()){
            if(c=='-')iosig=true;
            if(c==-1)return;
        }
        for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
        if(iosig)x=-x;
    }
    inline char readchar(){
        static char c;
        for(c=read();!isalpha(c);c=read())
        if(c==-1)return 0;
        return c;
    }
    const int OUT_LEN = 10000000;
    char obuf[OUT_LEN],*ooh=obuf;
    inline void print(char c) {
        if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
        *ooh++=c;
    }
    template<class T>
    inline void print(T x){
        static int buf[30],cnt;
        if(x==0)print('0');
        else{
            if(x<0)print('-'),x=-x;
            for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
            while(cnt)print((char)buf[cnt--]);
        }
    }
    inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
    int n,m,f[N],fi[N],ne[M],b[M],fa[N],cir[N];
    int h,t,q[N*2],ans,dep[N],dfn[N],low[N],ind,E;
    void dp(int u,int st){
        int len=0,h=1,t=0;
        for(int i=u;i!=st;i=fa[i])cir[++len]=i;cir[++len]=st;
        for(int i=1;i<=len/2;i++)swap(cir[i],cir[len-i+1]);
        for(int i=1;i<=len;i++)cir[i+len]=cir[i];
        for(int i=1;i<=len*2;i++){
            while(h<=t&&i-q[h]>len/2)h++;
            if(h<=t)ans=max(ans,f[cir[q[h]]]+f[cir[i]]+i-q[h]);
            while(h<=t&&f[cir[q[t]]]<f[cir[i]])t--;
            q[++t]=i;
        }
        for(int i=u;i!=st;i=fa[i]){
            f[st]=max(f[st],f[i]+min(dep[i]-dep[st],dep[u]-dep[i]+1));
        }
    }
    void tarjan(int u,int pre){
        dfn[u]=low[u]=++ind,fa[u]=pre,dep[u]=dep[pre]+1;
        for(int i=fi[u];i;i=ne[i]){
            int v=b[i];
            if(!dfn[v]){
                tarjan(v,u);
                low[u]=min(low[u],low[v]);
                if(low[v]>dfn[u])
                ans=max(ans,f[u]+f[v]+1),f[u]=max(f[u],f[v]+1);
            }
            else if(v!=pre)low[u]=min(low[u],dfn[v]);
        }
        for(int i=fi[u];i;i=ne[i]){
            int v=b[i];
            if(fa[v]!=u&&dfn[v]>dfn[u])
            dp(v,u);
        }
    }
    void add(int x,int y){
        ne[++E]=fi[x],fi[x]=E,b[E]=y;
    }
    int main(){
        read(n),read(m);
        for(int i=1;i<=m;i++){
            int k,s; read(k),read(s);
            for(int j=1;j<k;j++){
                int x; read(x);
                add(s,x),add(x,s),s=x;
            }
        }
        tarjan(1,0);
        for(int i=1;i<=n;i++)ans=max(ans,f[i]);
        printf("%d
    ",ans);
    }
    
  • 相关阅读:
    实现简单HttpServer案例
    实现简单Mybatis案例
    python 判断文件和文件夹是否存在的方法 和一些文件常用操作符
    常用模块学习
    python格式化输出
    ubuntu 配置vim编辑器
    linux 安装python3.x
    python属性限制 __slots__
    选课系统作业
    通过sorted获取dict的所有key值或者value值
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10057260.html
Copyright © 2020-2023  润新知