黑暗之魂(JZOJ)

题目

 题解

思路:

自环重边可以特判然后就变成了找树上的直径最大,答案加1即可

否则这就是一棵基环树,找到这个环,然后求出以环上的每个节点为根的最大直径,然后考虑在环上做贡献。

对于环上的每个点,先求出环的总长summ,显然对于i,与它贡献的点j一定满足sum_{i} + sum_{j} <= summ / 2,sum[i]表示从起点到i的环上路径长,其中起点可以随便给

然后破环成链,因为求的是最大,直接用单调队列维护即可。至于怎样找环,可以使用拓扑排序,也可以直接DFS

注意

拓扑排序不要写错,先判断这个点是否在环上,然后第二次连边时不要脸度数仍为2的边

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 1e6 + 3;
inline char GetChar(){
    static char buf[10001],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,10001,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int &n){
    short f=1;
    long long x=0;
    char c=GetChar();
    while(isdigit(c)==false){
        if(c=='-'){
            f=-1;
		}
        c=GetChar();
    }
    while(isdigit(c)==true){
    	x=((x<<3)+(x<<1)+(c^48));
        c=GetChar();
    }
    n=x*f;
}
struct edge{
    int v , w;
    edge(){}
    edge( int V, int W ){
        v = V , w = W;
    }
};
vector<edge>G[MAXN] , G1[MAXN];
int d[MAXN] , n;
queue<int>q;
ll dp[MAXN][2] , maxx , len[MAXN<<1] , dp1[MAXN<<1];
void dfs( int x , int f , int yuan ){
    for( int i = 0 ; i < G1[x].size() ; i ++ ){
        int v= G1[x][i].v , w = G1[x][i].w;
        if( v == f ) continue;
        dfs( v , x , yuan );
        if( dp[v][0] + w > dp[x][0] )
            dp[x][1] = dp[x][0] , dp[x][0] = dp[v][0] + w;
        else if( dp[v][0] + w > dp[x][1] )
            dp[x][1] = dp[v][0] + w;
    }
    maxx = max( maxx , dp[x][1] + dp[x][0] );
}
void dfs2( int x , int f , int yuan ){
    for( int i = 0 ; i < G[x].size() ; i ++ ){
        int v= G[x][i].v , w = G[x][i].w;
        if( v == f ) continue;
        dfs2( v , x , yuan );
        if( dp[v][0] + w > dp[x][0] )
            dp[x][1] = dp[x][0] , dp[x][0] = dp[v][0] + w;
        else if( dp[v][0] + w > dp[x][1] )
            dp[x][1] = dp[v][0] + w;
    }
    maxx = max( maxx , dp[x][1] + dp[x][0] );
}
bool vis[MAXN];
int s[MAXN<<1] , ncnt , head , tail , que[MAXN<<1];
int X[MAXN] , Y[MAXN] , W[MAXN];
ll quan;
inline void dfs1( int x , int st , int f ){
    s[++ncnt] = x;vis[x] = 1;
    for( int i = 0 ; i < G[x].size() ; i ++ ){
        int v= G[x][i].v;
        if( v == f ) continue;
        if( d[v] == 2 && !vis[v] ){
            quan += G[x][i].w;
            dp1[ncnt+1] = dp[v][0];
            len[ncnt+1] = len[ncnt] + G[x][i].w;
            dfs1( v , st , x );

        }
        else if( v == st ){
            quan += G[x][i].w;
            return ;
        }
    }
}
int oo[MAXN];
bool cmp( int x , int y ){
	if( X[x] ^ X[y] )
		return X[x] < X[y];
	if( Y[x] ^ Y[y] )
	return Y[x] < Y[y];
	return W[x] < W[y];
}
int main(){
    Read( n );
    bool fl = 0;
    for( int i = 1 ; i <= n ; i ++ ){
       Read( X[i] );Read( Y[i] );Read( W[i] );
       if( X[i] > Y[i] ) swap( X[i] , Y[i] );
        oo[i] = i;
    }
    sort( oo + 1 , oo + n + 1 , cmp ) ;
	for( int i = 1 ; i <= n ; i ++ ){
		if( (X[oo[i]] == X[oo[i-1]] && Y[oo[i]] == Y[oo[i-1]]) || X[oo[i]] == Y[oo[i]] ) { fl = 1; continue;}
		int x = X[oo[i]] , y = Y[oo[i]] , w = W[oo[i]];
		d[x] ++ , d[y] ++;
        G[x].push_back( edge( y , w ) );
         G[y].push_back( edge( x , w ) );
	}
    if( fl ){
        dfs2( 1 , 0 , 1 );
        printf( "%lld" , maxx + 1 );
        return 0;
    }
    for( int i = 1;  i <= n ; i ++ ){
        if( d[i] == 1) {
            q.push(  i );
            d[i] --;
        }
    }
    while( !q.empty() ){
        int x = q.front();
        q.pop();
        for( int i = 0 ; i <G[x].size() ; i ++ ){
            int v= G[x][i].v;
            d[v] --;
            if( d[v] == 1 ){
                q.push( v );
                d[v] --;
            }
        }
    }
    for( int i = 1 ; i <= n ; i ++ ){
        int x = X[i] , y = Y[i] , w = W[i];
        if( d[x] == 2 || d[y] == 2 ) continue;
        G1[x].push_back( edge( y , w ) );
        G1[y].push_back( edge( x , w ) );
    }
    for( int i = 1 ; i <= n ; i ++ ){
        if( d[i] == 2 ){
            for( int j = 0 ; j < G[i].size() ; j ++ ){
                int v = G[i][j].v , w = G[i][j].w;
                if( d[v] == 2 ) continue;
                dfs( v , i , i );
                if( dp[v][0] + w > dp[i][0] )
                    dp[i][1] = dp[i][0] , dp[i][0] = dp[v][0] + w;
                else if( dp[v][0] + w > dp[i][1] )
                    dp[i][1] = dp[v][0] + w;
                maxx = max( maxx , dp[i][1] + dp[i][0] );
            }
        }
    }
    for( int i = 1 ; i <= n ; i ++ ){
        if( d[i] == 2 ){
            len[1] = 0;dp1[1] = dp[i][0];
            dfs1( i , i , 0 );
            break;
        }
    }
    for( int i = 1 ; i <= ncnt ; i ++ ){
        len[i+ncnt] = len[i] + quan;
        dp1[i+ncnt] = dp1[i];
    }
    ncnt *= 2;
    int last = 1;
    head = 1;
    for( int i = 2 ; i <= ncnt / 2 ; i ++ ){
        if( ( len[i] - len[1] ) * 2 <= quan ){
            while( head <= tail && len[que[tail]] + dp1[que[tail]] < len[i] + dp1[i] ) tail --;
            que[++tail] = i;
            last = i;
        }
        else break;
    }
    for( int i = 1 ; i <= ncnt / 2 ; i ++ ){
        while( head <= tail && ( (len[que[head]] - len[i] ) * 2 > quan || que[head] == i ) ) head ++;
        last = max( last , i );
        while( last + 1 <= ncnt && last + 1 != i + ncnt && (len[last+1] - len[i] ) * 2 <= quan ){
            while( head <= tail && dp1[last+1] + len[last+1] > dp1[que[tail]] + len[que[tail]] ) tail --;
            que[++tail] = last + 1;last ++;
        }
        if( head <= tail )
        maxx = max( maxx , dp1[i] + dp1[que[head]] + len[que[head]] - len[i] );
    }
    printf( "%lld" , maxx + 1 );
    return 0;
}

冗长无比...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值