zoukankan      html  css  js  c++  java
  • [IOI2008]Island

    题目大意:

    找基环树直径

    (这个题输入给出的是内向基环树(虽然是无向边))

    存在两种情况:

    1.直径在树上。

    2.直径从树里走到环上,再走进另外一个树里。

    首先dfs找到环。

    第一种直接树形dp。dp[i]i往下最长路径。还能用来求第二种情况。

    第二种,找到环之后,断环成链,复制一倍。求的是,选择距离小于环长的两个点,贡献是两个点的dp[i],和两个点之间的距离。这个用单调队列优化dp即可。

    bzoj会爆栈mmp

    如果你是ywy可以bfs求树形dp

    其实,这是一个内向基环树,所以,直接topo排序,从叶子往上面topo

    即可求得dp,还能求得环。

    代码:(dfs爆栈版)

    #pragma comment(linker, "/STACK:102400000,102400000")
    #include<bits/stdc++.h>
    #define il inline
    #define reg register int 
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    void rd(int &x){
        char ch;x=0;
        while(!isdigit(ch=getchar()));
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    }
    namespace Miracle{
    const int N=1e6+5;
    int n;
    struct node{
        int nxt,to;
        ll val;
    }e[2*N];
    int hd[N],cnt=1;
    void add(int x,int y,int z){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        e[cnt].val=z;
        hd[x]=cnt;
    }
    bool vis[N];
    bool on[N];//on the huan
    bool in[N];
    int to[N],v[N];
    int sta[N],top;
    int len;//huan chang
    int mem[2*N],tot;
    ll cos[2*N];
    int q[2*N],l,r;
    ll f[N];
    ll ans;
    ll sum;
    ll zhi;
    bool fl;
    void dfs(int x,int in_edge){
    //    cout<<" dfs "<<x<<" "<<fl<<" "<<top<<endl;
        vis[x]=1;
        sta[++top]=x;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(i==(in_edge^1)) continue;
            if(!vis[y]){
                dfs(y,i);
            }
            else if(!fl){
                fl=true;
            //    cout<<" find "<<top<<" : "<<sta[top]<<endl;
                int z;
                do{
                    z=sta[top];
                    on[z]=1;
                    mem[++len]=z;
                    top--;
                }while(z!=y);
            }
        }
        if(sta[top]==x) --top;//warning!!!
    }
    void dp(int x,int fa){//find farthest
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            if(on[y]) continue;
            dp(y,x);
            zhi=max(zhi,f[x]+e[i].val+f[y]);
            f[x]=max(f[x],e[i].val+f[y]);
        }
    }
    ll wrk(int st){
        sum=0;
        len=0;
        fl=false;top=0;
        dfs(st,0);
        
        for(reg i=1;i<=len;++i){
            zhi=0;
            dp(mem[i],0);
            sum=max(sum,zhi);
            mem[i+len]=mem[i];
        }
        l=1,r=0;
        cos[1]=0;
        for(reg i=2;i<=2*len;++i){
            cos[i]=(to[mem[i]]==mem[i-1])?v[mem[i]]:v[mem[i-1]];
            cos[i]+=cos[i-1];
        }
        for(reg i=1;i<=2*len;++i){
            while(l<=r&&i-q[l]>=len) ++l;
            if(i!=1) sum=max(sum,f[mem[q[l]]]-cos[q[l]]+cos[i]+f[mem[i]]);
            while(l<=r&&f[mem[q[r]]]-cos[q[r]]<=f[mem[i]]-cos[i]) --r;
            q[++r]=i;
        }
        return sum;
    }
    int main(){
        rd(n);int x;int z;
        for(reg i=1;i<=n;++i){
            rd(x);rd(z);
            to[i]=x;
            v[i]=z;
            add(i,x,z);add(x,i,z);
        }
        for(reg i=1;i<=n;++i){
            if(!vis[i]){
                ans+=wrk(i);
            }
        }
        printf("%lld",ans);
        return 0;
    }
    
    }
    int main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2018/11/4 9:27:26
    */
  • 相关阅读:
    Single Number 解答
    Minimum Size Subarray Sum 解答
    Valid Anagram 解答
    Count Primes 解答
    fullCalendar 日历显示每天数据调用方法实践
    jqGrid列的统计
    关于 asp.net Web Api 上传文件请求内容过大404错误记录
    My97DatePicker只显示月份
    js 宏微任务执行顺序
    git 等官网下载慢方法
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9903327.html
Copyright © 2011-2022 走看看