• P4381 [IOI2008]Island(基环树)


    本题是基环树模板题,但是有一点要注意,特判两元环是必要的

    因为两元环中,我们要选权值大的两条边组成的直径,而多元环则不用在意,因为每两个点之间只有一条边

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e6+1e5;
    const int mod=998244353;
    int h[N],ne[N*2],e[N*2],w[N*2],idx;
    int vis[N],st[N];
    ll d[N],dt[N];
    int id[N];
    ll a[N*2],b[N*2];
    queue<int> q;
    int in[N];
    void add(int a,int b,int c){
        e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
    }
    void dfs0(int u,int fa){
        st[u]=1;
        if(in[u]==1)
            q.push(u);
        for(int i=h[u];i!=-1;i=ne[i]){
            int j=e[i];
            if(st[j])
                continue;
            dfs0(j,u);
        }
    }
    ll res;
    int topo(){
        int x;
        while(q.size()){
            int t=q.front();
            q.pop();
            vis[t]=1;
            for(int i=h[t];i!=-1;i=ne[i]){
                int j=e[i];
                if(vis[j])
                    continue;
                res=max(res,dt[t]+dt[j]+w[i]);
                dt[j]=max(dt[j],dt[t]+w[i]);
                in[j]--;
                if(in[j]==1){
                    q.push(j);
                }
                else{
                    x=j;
                }
            }
        }
        return x;
    }
    int visc[N];
    int num;
    void dfs(int u,int fa){
        visc[u]=1;
        id[++num]=u;
        int i;
        for(i=h[u];i!=-1;i=ne[i]){
            int j=e[i];
            if(j==fa||vis[j]||visc[j])
                continue;
            d[j]=d[u]+w[i];
            dfs(j,u);
        }
    }
    int qq[N];
    ll solve(int u){
        res=0;
        int x=u;
        if(q.size())
            x=topo();
        num=0;
        dfs(x,x);
        ll len=d[id[num]];
        int cnt=0;
        if(num==2){
            int sum=0;
            for(int i=h[id[num]];i!=-1;i=ne[i]){
                int j=e[i];
                if(j==id[1]){
                    sum=max(sum,w[i]);
                }
            }
            len+=sum;
        }
        else{
            for(int i=h[id[num]];i!=-1;i=ne[i]){
                int j=e[i];
                if(j==id[1]){
                    len+=w[i];
                    break;
                }
            }
        }
        //cout<<len<<endl;
        for(int i=1;i<=num;i++){
            a[i]=dt[id[i]];
            a[i+num]=dt[id[i]];
            b[i]=d[id[i]];
            b[i+num]=len+d[id[i]];
        }
        int hh=0,tt=-1;
        for(int i=1;i<=2*num;i++){
            while(hh<=tt&&i-qq[hh]>=num)
                hh++;
            if(hh<=tt) res=max(res,1ll*a[i]+b[i]+a[qq[hh]]-b[qq[hh]]);
            while(hh<=tt&&(a[i]-b[i])>=a[qq[tt]]-b[qq[tt]])
                tt--;
            qq[++tt]=i;
        }
        return res;
    }
    int main(){
        //ios::sync_with_stdio(false);
        memset(h,-1,sizeof h);
        int i;
        int n;
        cin>>n;
        for(i=1;i<=n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(i,u,v);
            add(u,i,v);
            in[u]++;
            in[i]++;
        }
        ll ans=0;
        for(i=1;i<=n;i++){
            if(!st[i]){
                dfs0(i,-1);
                ans+=solve(i);
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    3.for in循环
    2.break与continue
    1.XHTML框架结构
    lamda表达式在EF中的应用
    View数据呈现相关技术
    ASP.NET MVC 4 技术讲解
    ASP.NET MVC 相关的社群与讨论区
    C# 随机红包算法
    圆圈里带 小写字母,大写字母
    使用SQL语句 检测 MSSQL死锁
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13408073.html
Copyright © 2020-2023  润新知