首页 > 其他 > 详细

bzoj 2809 左偏树\平衡树启发式合并

时间:2014-03-29 20:32:24      阅读:543      评论:0      收藏:0      [点我收藏+]

  首先我们对于一颗树,要选取最多的节点使得代价和不超过m,那么我们可以对于每一个节点维护一个平衡树,平衡树维护代价以及代价的和,那么我们可以在logn的时间内求出这个子树最多选取的节点数,然后对于一个节点的平衡树我们可以由他的子节点启发式合并而来,时间复杂度nlog^2n。

  这道题还可以用左偏树来解决,左偏树为一种可合并堆,合并,删除,插入都在logn内完成,那么这道题的时间复杂度还可以nlogn。

  反思:我写的是左偏树的,手残把value打成cost了= =,查了半天。

 

bubuko.com,布布扣
/**************************************************************
    Problem: 2809
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:3604 ms
    Memory:8060 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <algorithm>
#define maxn 100010
#define LL long long
 
using namespace std;
 
int n,m,l;
int left[maxn],right[maxn];
int pre[maxn],other[maxn],last[maxn];
LL ans;
LL cost[maxn],value[maxn],size[maxn],sum[maxn];
 
void connect(int x,int y) {
    pre[++l]=last[x];
    last[x]=l;
    other[l]=y;
}
 
int combine(int x,int y) {
    if ((!x)||(!y)) return x+y;
    if (cost[x]<cost[y]) swap(x,y);
    right[x]=combine(right[x],y);
    sum[x]=sum[left[x]]+sum[right[x]]+cost[x];
    size[x]=size[left[x]]+size[right[x]]+1;
    return x;
}
 
int work(int x) {
    sum[x]=cost[x]; size[x]=1;
    int rot=x;
    for (int p=last[x];p;p=pre[p]) rot=combine(rot,work(other[p]));
    while (sum[rot]>m) rot=combine(left[rot],right[rot]);
    ans=max(ans,value[x]*size[rot]);
    return rot;
}
 
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) {
        int x; scanf("%d%lld%lld",&x,&cost[i],&value[i]);
        if (x) connect(x,i);
    }
    work(1);
    printf("%lld\n",ans);
    return 0;
}
bubuko.com,布布扣

bzoj 2809 左偏树\平衡树启发式合并,布布扣,bubuko.com

bzoj 2809 左偏树\平衡树启发式合并

原文:http://www.cnblogs.com/BLADEVIL/p/3632413.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!