题目大意:给定一棵树,选定一棵子树中的一些点,薪水和不能超过m,求点的数量*子树根节点的领导能力的最大值

考虑对于每一个节点,我们维护一种数据结构,在当中贪心寻找薪金小的雇佣。

每一个节点暴力重建一定不行。我们考虑可并数据结构。每一个节点将子节点的信息直接合并就可以

能够用启示式合并的Treap。也能够用可并堆

今天特意去学了这玩应0.0 先写了左偏树 然后又写了下随机堆…… 后者速度上更快一些 只是建议从左偏树開始学起

总之平衡树常数各种大就是了0.0

Treap+启示式合并

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
typedef long long ll;
struct abcd{
abcd *ls,*rs;
int key;
int cnt,siz;
ll num,sum;
abcd (ll x,int y);
void Maintain();
}*null=new abcd(0,0),*tree[M];
struct edge{
int to,next;
}table[M];
int head[M],tot;
int n,root;
ll m,ans,leadership[M];
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
abcd :: abcd(ll x,int y)
{
ls=rs=null;
sum=x*y;
num=x;
cnt=siz=y;
key=y?rand():0;
}
void abcd :: Maintain()
{
siz=ls->siz+rs->siz+cnt;
sum=ls->sum+rs->sum+num*cnt;
}
void Zig(abcd *&x)
{
abcd *y=x->ls;
x->ls=y->rs;
y->rs=x;
x=y;
x->rs->Maintain();
}
void Zag(abcd *&x)
{
abcd *y=x->rs;
x->rs=y->ls;
y->ls=x;
x=y;
x->ls->Maintain();
}
void Insert(abcd *&x,ll y,int z)
{
if(x==null)
{
x=new abcd(y,z);
return ;
}
if(y==x->num)
x->cnt+=z;
else if(y<x->num)
{
Insert(x->ls,y,z);
if(x->ls->key>x->key)
Zig(x);
}
else
{
Insert(x->rs,y,z);
if(x->rs->key>x->key)
Zag(x);
}
x->Maintain();
}
int Query(abcd *x,ll y)
{
if(x==null)
return 0;
ll temp=x->ls->sum;int re=0;
if(y<=temp) return Query(x->ls,y);
re+=x->ls->siz;y-=temp;
if(y<=x->num*x->cnt)
return re+y/x->num;
re+=x->cnt;y-=x->num*x->cnt;
return re+Query(x->rs,y);
}
void Decomposition(abcd *&x,int y)
{
if(x==null)
return ;
Decomposition(x->ls,y);
Decomposition(x->rs,y);
Insert(tree[y],x->num,x->cnt);
delete x;
x=null;
}
void Tree_DP(int x)
{
int i;
for(i=head[x];i;i=table[i].next)
{
Tree_DP(table[i].to);
if(tree[x]->siz<tree[table[i].to]->siz)
swap(tree[x],tree[table[i].to]);
Decomposition(tree[table[i].to],x);
}
ans=max(ans,leadership[x]*Query(tree[x],m));
}
int main()
{ //freopen("2809.in","r",stdin);
//freopen("2809.out","w",stdout); int i,fa;
ll x;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d%lld%lld",&fa,&x,&leadership[i]);
if(!fa) root=i;
else Add(fa,i);
tree[i]=new abcd(x,1);
}
Tree_DP(root);
cout<<ans<<endl;
}
//lld!!

左偏树

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
struct abcd{
abcd *ls,*rs;
int num,h;
abcd(int x);
}*null=new abcd(0),*tree[M];
struct edge{
int to,next;
}table[M];
int head[M],tot;
int n,m,root,leadership[M],sum[M],size[M];
long long ans;
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
abcd :: abcd(int x)
{
ls=rs=null;
num=x;
if(x) h=0;
else h=-1;
}
abcd* Merge(abcd *x,abcd *y)
{
if(x==null) return y;
if(y==null) return x;
if(x->num<y->num)
swap(x,y);
x->rs=Merge(x->rs,y);
if(x->ls->h<x->rs->h)
swap(x->ls,x->rs);
x->h=x->rs->h+1;
return x;
}
void Tree_DP(int x)
{
int i;
for(i=head[x];i;i=table[i].next)
{
Tree_DP(table[i].to);
tree[x]=Merge(tree[x],tree[table[i].to]);
sum[x]+=sum[table[i].to];
size[x]+=size[table[i].to];
while(sum[x]>m)
{
sum[x]-=tree[x]->num;
--size[x];
tree[x]=Merge(tree[x]->ls,tree[x]->rs);
}
}
ans=max(ans,(long long)size[x]*leadership[x]);
}
int main()
{
int i,fa,x;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&fa,&x,&leadership[i]);
if(!fa) root=i;
else Add(fa,i);
tree[i]=new abcd(x);
sum[i]=x;
size[i]=1;
}
Tree_DP(root);
cout<<ans<<endl;
}

随机堆

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
struct abcd{
abcd *ls,*rs;
int num;
abcd(int x);
}*null=new abcd(0),*tree[M];
struct edge{
int to,next;
}table[M];
bool son;
int head[M],tot;
int n,m,root,leadership[M],sum[M],size[M];
long long ans;
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
abcd :: abcd(int x)
{
ls=rs=null;
num=x;
}
abcd* Merge(abcd *x,abcd *y)
{
if(x==null) return y;
if(y==null) return x;
if(x->num<y->num)
swap(x,y);
if(son^=1)
x->rs=Merge(x->rs,y);
else
x->ls=Merge(x->ls,y);
return x;
}
void Tree_DP(int x)
{
int i;
for(i=head[x];i;i=table[i].next)
{
Tree_DP(table[i].to);
tree[x]=Merge(tree[x],tree[table[i].to]);
sum[x]+=sum[table[i].to];
size[x]+=size[table[i].to];
while(sum[x]>m)
{
sum[x]-=tree[x]->num;
--size[x];
tree[x]=Merge(tree[x]->ls,tree[x]->rs);
}
}
ans=max(ans,(long long)size[x]*leadership[x]);
}
int main()
{
int i,fa,x;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&fa,&x,&leadership[i]);
if(!fa) root=i;
else Add(fa,i);
tree[i]=new abcd(x);
sum[i]=x;
size[i]=1;
}
Tree_DP(root);
cout<<ans<<endl;
}

BZOJ 2809 APIO2012 dispatching Treap+启示式合并 / 可并堆的更多相关文章

  1. BZOJ 2809 APIO 2012 dispatching 平衡树启示式合并

    题目大意:给出一棵树,每个节点有两个值,各自是这个忍者的薪水和忍者的领导力.客户的惬意程度是这个点的领导力乘可以取得人数.前提是取的人的薪水总和不超过总的钱数. 思路:仅仅能在子树中操作.贪心的想,我 ...

  2. BZOJ 2809: [Apio2012]dispatching( 平衡树 + 启发式合并 )

    枚举树上的每个结点做管理者, 贪心地取其子树中薪水较低的, 算出这个结点为管理者的满意度, 更新答案. 用平衡树+启发式合并, 时间复杂度为O(N log²N) ------------------- ...

  3. bzoj 2809: [Apio2012]dispatching -- 可并堆

    2809: [Apio2012]dispatching Time Limit: 10 Sec  Memory Limit: 128 MB Description 在一个忍者的帮派里,一些忍者们被选中派 ...

  4. BZOJ 2809: [Apio2012]dispatching(左偏树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2809 题意: 思路:最简单的想法就是枚举管理者,在其子树中从薪水低的开始选起,但是每个节点都这样处理 ...

  5. BZOJ 2809 [Apio2012]dispatching(斜堆+树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2809 [题目大意] 给出一棵树,求出每个点有个权值,和一个乘算值,请选取一棵子树, 并 ...

  6. bzoj 2809: [Apio2012]dispatching

    #include<cstdio> #include<algorithm> #define M 1000005 using namespace std; long long an ...

  7. BZOJ 2809: [Apio2012]dispatching [斜堆]

    题意:主席树做法见上一题 我曾发过誓再也不写左偏树(期末考试前一天下午5个小时没写出棘手的操作) 于是我来写斜堆啦 从叶子往根合并,维护斜堆就行了 题目连拓扑序都给你了... 说一下斜堆的操作: 合并 ...

  8. BZOJ 2809: [Apio2012]dispatching(可并堆 左偏树板题)

    这道题只要读懂题目一切好说. 给出nnn个点的一棵树,每一个点有一个费用vvv和一个领导力aaa,给出费用上限mmm.求下面这个式子的最大值ax∗∣S∣ ( S⊂x的子树, ∑iv[i]≤m )\la ...

  9. BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]

    传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边 ...

随机推荐

  1. 浅谈Jquery的使用下篇

    上一篇我们已经探讨了Jquery的有关的内容,简单的选择器以及一些Jquery的属性事件和方法等内容,让我们简单的学到了Jquery的比较基础的内容,下面我们就来探讨Jquery的一些其它的内容,比如 ...

  2. check————身份证

    -- Access 不支持 Substring 查询,可以替换为 mid 查询. select 序号,姓名,身份证号,性别from 身份表where (len(身份证号)<>15 and ...

  3. h和.cpp文件的区别

    关于头文件和源文件的分别 首先,我们可以将所有东西都放在一个.cpp文件内. 然后编译器就将这个.cpp编译成.obj,obj是什么东西? 就是编译单元了.一个程序,可以由一个编译单元组成, 也可以有 ...

  4. C# 数据访问编码需要遵循的几个规范

    一,链接打开之后必须关闭,否则会占用系统空间 SqlConnection conn=new SqlConnection(CONNECTIONSTRING); conn.open(); conn.clo ...

  5. 快速排序的时间复杂度nlogn是如何推导的??

    本文以快速排序为例,推导了快排的时间复杂度nlogn是如何得来的,其它算法与其类似. 对数据Data = { x1, x2... xn }: T(n)是QuickSort(n)消耗的时间: P(n)是 ...

  6. 【分享】深入浅出WPF全系列教程及源码

    本人10月份提出离职,可是交接非常慢,预计年底才会交接完,趁着交接之际,自学了一下WPF,由于这是微软未来的发展趋势,自WIN7以来包含前不久公布的WIN8,核心还是WPF,在此,将自己的学习成果做一 ...

  7. POJ 1330 Nearest Common Ancestors(Tarjan离线LCA)

    Description A rooted tree is a well-known data structure in computer science and engineering. An exa ...

  8. ProgressDialog使用汇总

    ProgressDialog使用  ProgressDialog 从继承AlertDialog,AlertDialog继承自Dialog,实现DialogInterface接口. ProgressDi ...

  9. qt宽字符串中文乱码(codec->toUnicode值得学习)

    乱码原因: QT使用的是utf-8 简体中文版的windows操作系统及其应用软件默认都是ANSI/GBK编码.而且这里应该是宽字符串. 多字节ANISGB 宽字符UNICODE 多字节显示标准字符的 ...

  10. mysql iot 主键自增列问题

    mysql 如何避免热点块? 主键按sn自增列 Oracle 可以通过翻转索引 比如 插入101 102 103 104 变成101 201 301 401 分散数据 反转索引坏处,无法index r ...