zoukankan      html  css  js  c++  java
  • [SHOI2008]仙人掌图 II——树形dp与环形处理

    题意:

    给定一个仙人掌,边权为1

    距离定义为两个点之间的最短路径

    直径定义为距离最远的两个点的距离

    求仙人掌直径

     

    题解:

    类比树形dp求直径。

    f[i]表示i向下最多多长

    处理链的话,直接dp即可。

    处理环的话,类似点双tarjan,把环上的点都拉出来。

    先考虑拼接更新答案。断环成链复制一倍,为了保证最短路,答案必须只能是f[i]+f[j]+i-j (i-len/2<=j<i)

    单调队列优化。

    直接i-j即可,另一半的绕环会在复制后的那里处理。

    然后更新f[x],直接找环上其他的元素,距离就是两段距离的较小值。

    因为tarjan本质上是一棵dfs树,所以处理环的时候元素都是x的儿子,儿子们的f必然已经处理。

     

    tarjan点双时注意:

     下面的写法是错误的。

    因为,点双时的割点可能属于多个dcc,所以可能y不和x紧挨着存储。会弹出多余的东西。

    黑色是仙人掌,红色是dfs树。A,B是V-DCC

    可能访问x之后,先访问了A,因为father的dfn小,所以不能弹栈。A的红色部分在栈里保存。

    然后从y进入,访问B。发现访问完了之后,可以弹栈,

    如果是第二种写法,那么会等到栈顶是x才停止,那么会把A中的点也弹出来。

    根本知道弹出来的是什么。。。。

    第一种的话,会在弹出y之后停止。没有问题。

    症结就因为x属于两个V-DCC

    还要注意:

    多次用queue,必须保证在l<=r时才能更新答案。

    if(l<=r) ans=max(ans,f[mem[i]]+i+f[mem[q[l]]]-q[l]);

     代码:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=500000+5;
    int n,m;
    struct node{
        int nxt,to;
    }e[10*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int dfn[N],df,low[N];
    int f[N];
    int q[N],l,r;
    int ans;
    int sta[N],top,len;
    int mem[2*N],num;
    void wrk(int x){
        len=num;
        for(reg i=1;i<=num;++i) mem[i+num]=mem[i],ans=max(ans,f[mem[i]]);
        l=1,r=0;
        for(reg i=1;i<=2*num;++i){
            while(l<=r&&q[l]<i-len/2) ++l;
            if(l<=r) ans=max(ans,f[mem[i]]+i+f[mem[q[l]]]-q[l]);
            while(l<=r&&f[mem[q[r]]]-q[r]<f[mem[i]]-i) --r;
            q[++r]=i;
        }
        for(reg i=2;i<=num;++i){
            f[x]=max(f[x],f[mem[i]]+min(i-1,num+1-i));
        }
    }
    void tarjan(int x){
        //cout<<" tarjan "<<x<<" top "<<top<<endl;
        dfn[x]=low[x]=++df;
        sta[++top]=x;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
                if(dfn[x]<=low[y]){//find V-dcc
                    num=0;
                    mem[++num]=x;
                    int z;
                    do{
                        z=sta[top--];
                        mem[++num]=z;
                    }while(z!=y);
                    wrk(x);
                }
            }
            else low[x]=min(low[x],dfn[y]);
        }
    }
    int main(){
        rd(n);rd(m);int k,x,y;
        for(reg i=1;i<=m;++i){
            rd(k);rd(x);
            for(reg j=1;j<k;++j){
                rd(y);add(x,y);add(y,x);x=y;
            }
        }
        tarjan(1);
    //    for(reg i=1;i<=n;++i){
    //        cout<<i<<" : "<<f[i]<<endl;
    //    }
        printf("%d",ans);
        return 0;
    }
    
    }
    int main(){
    //    freopen("data.in","r",stdin);
    //    freopen("my.out","w",stdout);
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2018/11/30 7:44:32
    */
  • 相关阅读:
    java并发编程-Executor框架 + Callable + Future
    Executors Future Callable 使用场景实例
    大数据云平台Greenplum:多租户篇
    Kafka集成SparkStreaming
    CDH集群安装出现问题参考
    Cloudera Manager卸载笔记
    Hive去除重复数据操作
    032 搭建搜索微服务01----向ElasticSearch中导入数据--通过Feign实现微服务之间的相互调用
    SpringBoot工程常见报错汇总
    030 ElasticSearch----全文检索技术05---基础知识详解03-聚合
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10044213.html
Copyright © 2011-2022 走看看