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

 

posted @ 2020-07-31 10:03  朝暮不思  阅读(143)  评论(0编辑  收藏  举报