spoj 1825

这题貌似用启发式合并的话复杂度为nlogn,然而我不会,于是用 树状数组写的,复杂度 n(logn)2,跑了900多ms。 用树状数组有一个坑,就是树状数组的下表从1 开始,但是可能存在路径上关键节点为0的情况,那么我们给每条路径关键节点个数加一,就避免了这种情况。还有一个问题是如果根节点本身是关键节点的话,需要把两条路径的个数的和减1.

还有就是树状数组清空如果memset会超时,于是我记录了修改的节点进行复原。感觉好丑陋。。。

去学启发式合并的方法去了QAQ

#include <bits/stdc++.h>
using namespace std;
typedef int lint;
typedef long long LL;
const lint maxn = 200000 + 5;
const lint maxm = 400000 + 5;
const lint inf = 0x3f3f3f3f;
lint key[maxn],he[maxn],ne[maxm],ver[maxm],tot,b[maxn],k,cost[maxm],vis[maxn],cnt[maxn],g[maxn],sz[maxn],d[maxn],ans,root,sum;
void add_edge( lint x,lint y,lint c ){
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
    cost[tot]  = c;
}
void init_b( lint k ){
    for( lint i  = 0;i <= k;i++ ) b[i] = -inf;
}
lint lowbit( lint x ){
    return x&(-x);
}
void add( lint x,lint v ){
    while( x <= k ){
        b[x] = max(b[x], v);
        x += lowbit(x);
    }
}
lint ask( lint x ){
    lint re = -inf;
    while( x ){
        re = max(re, b[x]);
        x -= lowbit(x);
    }
    return re;
}
void init(){
    memset( he,0,sizeof(he) );
    memset( key,0,sizeof(key) );
    memset( vis,0,sizeof(vis) );
    tot = 1;
    ans = 0;
}
vector<lint> ve;
void dfs_cnt( lint x,lint f,lint dis,lint c ){
    cnt[x] = c;
    d[x] = dis;
    ve.push_back(x);
    if( key[x] ) { cnt[x]++; c++;}
    if(  !key[root] &&  k - c >= 1 )
        ans = max( ans,dis+ask( k-c ) );
    else if( key[root] && k+1-c >= 1 ){
        ans = max( ans,dis+ask( k+1-c ) );
    }
    for( lint cure = he[x];cure;cure = ne[cure] ){
        lint y = ver[cure];
        if( vis[y] || y == f ) continue;
        dfs_cnt( y,x,dis+cost[cure],c );
    }
}
void get_root(lint x,lint f)
{
    sz[x]=1;g[x]=0;
    for(int cure = he[x];cure;cure= ne[cure]){
        lint y = ver[cure];
        if( vis[y] || y == f ) continue;
            get_root(y,x);
            g[x]=max(g[x],sz[y]);
            sz[x]+=sz[y];
    }
    g[x]=max(g[x],sum-sz[x]);
    if(g[x]<g[root])root=x;
}
void init_b2( lint x ){
    while( x <= k ){
        b[x] = -inf;
        x += lowbit(x);
    }
}
vector<lint> ve2;
void dfs_div( lint x ){
    vis[x] = 1;
    if( key[x] ) add( 2,0 );
    else add(1,0);
    ve2.clear();
    for( lint cure = he[x];cure;cure = ne[cure] ){
        lint y = ver[cure];
        if( vis[y] ) continue;
        ve.clear();
        if( key[x] )
            dfs_cnt(  y,x,cost[cure],2 );
        else dfs_cnt( y,x,cost[cure],1 );
        for( lint i = 0;i < ve.size();i++ ){
            lint t = ve[i];
            ve2.push_back(t);
            add( cnt[t],d[t] );
        }
    }
    if( key[x] ) init_b2(2);
    else init_b2(1);
    for( lint i = 0;i < ve2.size();i++ ){
        init_b2( cnt[ve2[i]] );
    }
    for( lint cure = he[x];cure;cure = ne[cure] ){
        lint y = ver[cure];
        if( vis[y] ) continue;
        root = 0;sum = sz[y];
        get_root( y,x );
        dfs_div( root );
    }
}
int main() {
    lint n,m;
    scanf("%d%d%d",&n,&k,&m);
    k += 2;
    init();init_b(k);
    for( lint x,  i = 1;i <= m;i++ ){
        scanf("%d",&x);
        key[x] = 1;
    }
    for( lint x,y,c, i = 1;i <= n-1;i++ ){
        scanf("%d%d%d",&x,&y,&c);
        add_edge( x,y,c );
        add_edge( y,x,c );
    }
    sum = n;g[0] = n;root = 0;
    get_root( 1,0 );
    dfs_div(root);
    printf("%d",ans);
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值