• 岛屿(bzoj1791)


    1791: [Ioi2008]Island 岛屿

    Time Limit: 20 Sec  Memory Limit: 162 MB
    Submit: 2042  Solved: 461
    [Submit][Status][Discuss]

    Description

    你将要游览一个有N个岛屿的公园。从每一个岛i出发,只建造一座桥。桥的长度以Li表示。公园内总共有N座桥。尽管每座桥由一个岛连到另一个岛,但每座桥均可以双向行走。同时,每一对这样的岛屿,都有一艘专用的往来两岛之间的渡船。 相对于乘船而言,你更喜欢步行。你希望所经过的桥的总长度尽可能的长,但受到以下的限制。 • 可以自行挑选一个岛开始游览。 • 任何一个岛都不能游览一次以上。 • 无论任何时间你都可以由你现在所在的岛S去另一个你从未到过的岛D。由S到D可以有以下方法: o 步行:仅当两个岛之间有一座桥时才有可能。对于这种情况,桥的长度会累加到你步行的总距离;或者 o 渡船:你可以选择这种方法,仅当没有任何桥和/或以前使用过的渡船的组合可以由S走到D(当检查是否可到达时,你应该考虑所有的路径,包括经过你曾游览过的那些岛)。 注意,你不必游览所有的岛,也可能无法走完所有的桥。 任务 编写一个程序,给定N座桥以及它们的长度,按照上述的规则,计算你可以走过的桥的最大长度。 限制 2 <= N <= 1,000,000 公园内的岛屿数目。 1<= Li <= 100,000,000 桥i的长度。

    Input

    • 第一行包含N个整数,即公园内岛屿的数目。岛屿由1到N编号。 • 随后的N行每一行用来表示一个岛。第i 行由两个以单空格分隔的整数,表示由岛i筑的桥。第一个整数表示桥另一端的岛,第二个整数表示该桥的长度Li。你可以假设对於每座桥,其端点总是位于不同的岛上。

    Output

    你的程序必须向标准输出写出包含一个整数的单一行,即可能的最大步行距离。 注1:对某些测试,答案可能无法放进32-bit整数,你要取得这道题的满分,可能需要用Pascal的int64或C/C++的long long类型。 注2:在比赛环境运行Pascal程序,由标准输入读入64-bit数据比32-bit数据要慢得多,即使被读取的数据可以32-bit表示。我们建议把输入数据读入到32-bit数据类型。 评分 N不会超过4,000。

    Sample Input

    7
    3 8
    7 2
    4 2
    1 4
    1 9
    3 4
    2 3


    Sample Output

    24

    HINT

    这道题可以学到很多东西

    首先先以环中每个点为根求出最远能到达的距离

    然后最长链为环中某两点的距离再加上,这两点最远到达的距离

    然后具体怎么求这些东西呢

    首先求以环中每个点为根求出最远能到达的距离

    我们先标记每个点的入度,若一开始入度为一,则说明此点为叶子节点,然后通过不断向上求,并且不断删掉该点的叶子节点个数,就可以求到环上的点

    而最后环上的点必定入度为二,所以可以实现避免环上的点求最远距离,并且可以找出环来


    void topsort(){
         ll l=1,r=0;
         for (ll i=1;i<=n;i++) if(du[i]==1) Q[++r]=i;
         while(l<=r){
            ll u=Q[l];
            for (ll i=adj[u];i;i=bian[i].next){
                ll v=bian[i].v;
                if(du[v]>1){
                    d[c[u]]=max(d[c[u]],f[v]+f[u]+bian[i].w);
                    f[v]=max(f[v],f[u]+bian[i].w);
                    if((--du[v])==1) Q[++r]=v;
                }
            }
            l++;
         }
    }

    最后求环上的最远距离可以把环拆开复制成两倍做成一条链,便可以用单调队列方法求最值

    void getans(ll t,ll x){
         ll y=x;
         ll i,r,l=0;
         ll m=0;
         do{
            a[++m]=f[y];
            du[y]=1;
            for (i=adj[y];i;i=bian[i].next){
                ll v=bian[i].v;
                if(du[v]>1){
                    b[m+1]=b[m]+bian[i].w;
                    y=v;
                    break;
                }
            }
         }while(i);
         if(m==2){void getans(ll t,ll x){
         ll y=x;
         ll i,r,l=0;
         ll m=0;
         do{
            a[++m]=f[y];
            du[y]=1;
            for (i=adj[y];i;i=bian[i].next){
                ll v=bian[i].v;
                if(du[v]>1){
                    b[m+1]=b[m]+bian[i].w;
                    y=v;
                    break;
                }
            for (i=adj[y];i;i=bian[i].next){
                if(bian[i].v==x) {b[2]=max(b[2],bian[i].w);}
            }
            d[t]=max(d[t],f[x]+f[y]+b[2]);
            return ;
         }
         for (i=adj[y];i;i=bian[i].next){
            if(bian[i].v==x){
                b[m+1]=b[m]+bian[i].w;
                break;
            }
         }
         for (i=1;i<m;i++) {a[m+i]=a[i];b[m+i]=b[m+1]+b[i];}
         Q[l=r=1]=1;
         for (i=2;i<2*m;i++){
             while(l<=r&&i-Q[l]>=m) l++;
             d[t]=max(d[t],a[i]+a[Q[l]]+b[i]-b[Q[l]]);
             while(l<=r&&a[Q[r]]+b[i]-b[Q[r]]<=a[i]) r--;
             Q[++r]=i;
         }
    }
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    const int maxn=1000000+10;
    typedef long long ll;
    
    struct my{
           int v;
           int next;
           ll w;
    };
    
    my bian[maxn*2];
    int adj[maxn],n,c[maxn],du[maxn],Q[maxn*2];
    bool vis[maxn];
    ll f[maxn],fa,d[maxn],a[maxn*2],b[maxn*2];
    
    void myinsert(ll u,ll v,ll w){
         bian[++fa].v=v;
         bian[fa].next=adj[u];
         bian[fa].w=w;
         adj[u]=fa;
         du[v]++;
    }
    
    void dfs(ll x,ll t){
         c[x]=t;
         for (ll i=adj[x];i;i=bian[i].next){
                ll v=bian[i].v;
            if(!c[v]){
                dfs(v,t);
            }
         }
    }
    
    void topsort(){
         ll l=1,r=0;
         for (ll i=1;i<=n;i++) if(du[i]==1) Q[++r]=i;
         while(l<=r){
            ll u=Q[l];
            for (ll i=adj[u];i;i=bian[i].next){
                ll v=bian[i].v;
                if(du[v]>1){
                    d[c[u]]=max(d[c[u]],f[v]+f[u]+bian[i].w);
                    f[v]=max(f[v],f[u]+bian[i].w);
                    if((--du[v])==1) Q[++r]=v;
                }
            }
            l++;
         }
    }
    
    void getans(ll t,ll x){
         ll y=x;
         ll i,r,l=0;
         ll m=0;
         do{
            a[++m]=f[y];
            du[y]=1;
            for (i=adj[y];i;i=bian[i].next){
                ll v=bian[i].v;
                if(du[v]>1){
                    b[m+1]=b[m]+bian[i].w;
                    y=v;
                    break;
                }
            }//把环拆成链
         }while(i);
         if(m==2){
            for (i=adj[y];i;i=bian[i].next){
                if(bian[i].v==x) {b[2]=max(b[2],bian[i].w);}
            }
            d[t]=max(d[t],f[x]+f[y]+b[2]);
            return ;
         }
         for (i=adj[y];i;i=bian[i].next){
            if(bian[i].v==x){
                b[m+1]=b[m]+bian[i].w;
                break;把环的开头找到、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
            }
         }
         for (i=1;i<m;i++) {a[m+i]=a[i];b[m+i]=b[m+1]+b[i];}
         Q[l=r=1]=1;
         for (i=2;i<2*m;i++){
             while(l<=r&&i-Q[l]>=m) l++;
             d[t]=max(d[t],a[i]+a[Q[l]]+b[i]-b[Q[l]]);
             while(l<=r&&a[Q[r]]+b[i]-b[Q[r]]<=a[i]) r--;
             Q[++r]=i;
         }
    }
    
    int main(){
       // freopen("bzoj1791.in","r",stdin);
        //freopen("bzoj1791.out","w",stdout);
        scanf("%lld",&n);
        ll u,w;
        for (int i=1;i<=n;i++){
            scanf("%lld%lld",&u,&w);
            myinsert(u,i,w);
            myinsert(i,u,w);
        }
        ll t=0;
        for (ll i=1;i<=n;i++)
            if(!c[i]) {
                    ++t;
                    dfs(i,t);//标记每棵树
            }
        topsort();
        ll ans=0;
        for(ll i=1;i<=n;i++){
            if(du[i]>1&&!vis[c[i]]){
                vis[c[i]]=1;
                getans(c[i],i);
                ans+=d[c[i]];
            }
        }
        printf("%lld ",ans);
    return 0;
    }
  • 相关阅读:
    暑假日报-11
    暑假日报-10
    暑假日报-9
    暑假日报-8
    暑假日报-7
    暑假日报-6
    暑假日报-5
    暑假日报-4
    暑假日报-3
    第二次集训的每日感想
  • 原文地址:https://www.cnblogs.com/lmjer/p/9363946.html
Copyright © 2020-2023  润新知