treap启发式合并(BZOJ2809)||splay||左偏树
2015-03-06 21:59
363 查看
2809: [Apio2012]dispatching
Time Limit: 10 Sec Memory Limit:128 MB
Submit: 1477 Solved: 713
[Submit][Status]
Description
在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿。在这个帮派里,有一名忍者被称之为 Master。除了 Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者 发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递 人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,就不需要支付管理者的薪水。你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。写一个程序,给定每一个忍者
i的上级 Bi,薪水Ci,领导力L
i,以及支付给忍者们的薪水总预算 M,输出在预算内满足上述要求时顾客满意度的最大值。
1 ≤N ≤ 100,000忍者的个数;
1 ≤M ≤ 1,000,000,000 薪水总预算;
0 ≤Bi < i 忍者的上级的编号;
1 ≤Ci ≤ M 忍者的薪水;
1 ≤Li ≤ 1,000,000,000 忍者的领导力水平。
Input
从标准输入读入数据。第一行包含两个整数 N和 M,其中
N表示忍者的个数,M表示薪水的总预算。
接下来 N行描述忍者们的上级、薪水以及领导力。其中的第 i 行包含三个整Bi
, C i , L i分别表示第i个忍者的上级,薪水以及领导力。Master满足B i = 0,并且每一个忍者的老板的编号一定小于自己的编号Bi
< i。
Output
输出一个数,表示在预算内顾客的满意度的最大值。Sample Input
5 40 3 3
1 3 5
2 2 2
1 2 4
2 3 1
Sample Output
6HINT
如果我们选择编号为 1的忍者作为管理者并且派遣第三个和第四个忍者,薪水总和为 4,没有超过总预算 4。因为派遣了 2 个忍者并且管理者的领导力为 3,用户的满意度为 2 ,是可以得到的用户满意度的最大值。
题意:给一棵树,每个节点有C,L两个属性,找到一个点,使得在这个点的子节点中选出一些点,这些点的C的和小于M,得到一个值(选出节点的个数*此节点的L值),问这个值得最大值是多少
思路:首先DFS一次得到每个点的深度,然后按照深度从大到小依次向父节点合并。每次合并之后就是要在这个子树中找到最多的节点使得他们的C值不超过m,用treap就可以了
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> using namespace std; const int maxn=400010; typedef long long LL; int root[maxn],tot; int N; LL M,ans; LL L[maxn]; int head[maxn]; int num; struct E { int v,next; }edge[maxn]; struct Node { int ch[2]; int r; LL v; LL sum; int cnt; int s; void init(LL val,int p){v=val;ch[0]=ch[1]=0;cnt=s=p;r=rand();} int cmp(LL x)const { if(x==v)return -1; return x<v?0:1; } }tree[maxn*2]; void maintain(int x) { tree[x].s=tree[x].cnt; tree[x].s+=tree[tree[x].ch[0]].s+tree[tree[x].ch[1]].s; tree[x].sum=tree[tree[x].ch[0]].sum+tree[tree[x].ch[1]].sum+(LL)tree[x].cnt*tree[x].v; } void rotate(int &o,int d) { int k=tree[o].ch[d^1]; tree[o].ch[d^1]=tree[k].ch[d]; tree[k].ch[d]=o; maintain(o); maintain(k); o=k; } void insert(int &o,LL x,int cnt) { if(!o) { o=++tot; tree[o].init(x,cnt); } else { if(x==tree[o].v)tree[o].cnt+=cnt; else { int d=(x<tree[o].v?0:1); insert(tree[o].ch[d],x,cnt); if(tree[tree[o].ch[d]].r>tree[o].r) rotate(o,d^1); } } maintain(o); } void remove(int &o,LL x) { if(!o)return; int d=tree[o].cmp(x); if(d==-1) { int u=o; if(tree[o].ch[0]&&tree[o].ch[1]) { int d2=(tree[tree[o].ch[0]].r>tree[tree[o].ch[1]].r?1:0); rotate(o,d2); remove(tree[o].ch[d2],x); } else { if(!tree[o].ch[0])o=tree[o].ch[1]; else o=tree[o].ch[0]; } } else remove(tree[o].ch[d],x); if(o)maintain(o); } void add_edge(int fa,int v) { edge[num].v=v; edge[num].next=head[fa]; head[fa]=num++; } void merge(int &src,int &dest) { if(!src)return; merge(tree[src].ch[0],dest); merge(tree[src].ch[1],dest); insert(dest,tree[src].v,tree[src].cnt); remove(src,tree[src].v); } int query(int o,LL x) { if(!o)return 0; LL tmp=tree[o].v*tree[o].cnt; if(tree[tree[o].ch[0]].sum>=x)return query(tree[o].ch[0],x); else if(tree[tree[o].ch[0]].sum+tmp<x) return tree[tree[o].ch[0]].s+tree[o].cnt+query(tree[o].ch[1],x-tmp-tree[tree[o].ch[0]].sum); return tree[tree[o].ch[0]].s+(x-tree[tree[o].ch[0]].sum)/tree[o].v; } void dfs(int u) { for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; dfs(v); if(tree[root[u]].s<tree[root[v]].s) swap(root[u],root[v]); merge(root[v],root[u]); } ans=max(ans,L[u]*query(root[u],M)); } int main() { while(scanf("%d%lld",&N,&M)!=EOF) { tot=num=0; int st,u; memset(head,-1,sizeof(head)); memset(root,0,sizeof(root)); LL c; for(int i=1;i<=N;i++) { scanf("%d%lld%lld",&u,&c,&L[i]); if(!u)st=i; else add_edge(u,i); insert(root[i],c,1); } ans=0; dfs(st); printf("%lld\n",ans); } return 0; }
splay写法:
BZOJ2809 splay
下面的代码是改动了上面博客的二分:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> typedef long long ll; using namespace std; #define N 1100000 #define inf 0x6ffffffffffffffLL int ch [2],siz ,pre ; ll val ,sum ; int rank ; int e ,ne[N*2],v[N*2]; int b ,nn,n; ll m; ll L ,c ; void add(int x,int y){ ne[++nn]=e[x],e[x]=nn,v[nn]=y; } void up(int x){ siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1; sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x]; } void rotate(int x){ int y=pre[x],z=pre[y],k=(ch[y][0]==x); pre[ch[y][!k]=ch[x][k]]=y; pre[ch[x][k]=y]=x; pre[x]=z; if(z)ch[z][ch[z][1]==y]=x; up(y); } void splay(int x,int fa){ for(;pre[x]!=fa;){ int y=pre[x],z=pre[y]; if(z==fa)rotate(x); else if((ch[z][1]==y)==(ch[y][1]==x))rotate(y),rotate(x); else rotate(x),rotate(x); } up(x); } int cha(int x,int y){ int now=x,k; while(1){ k=(val[x]<val[y]); if(!ch[x][k]){ ch[y][0]=0,ch[y][1]=0; sum[y]=val[y]; siz[y]=1; ch[x][k]=y; pre[y]=x; splay(y,0); break; }else x=ch[x][k]; } return y; } int qu ,bo,he; int e1; void bing(int x,int y){ splay(x,0),splay(y,0);//这里的旋转是为了下面的一句话 if(siz[x]<siz[y])swap(x,y); for(qu[bo=he=1]=y;he>=bo;bo++){ e1=qu[bo]; if(ch[e1][0])qu[++he]=ch[e1][0]; if(ch[e1][1])qu[++he]=ch[e1][1]; } for(int i=1;i<=he;i++)x=cha(x,qu[i]); } int getcnt(int r,ll m) { if(!r)return 0; if(sum[ch[r][0]]>=m)return getcnt(ch[r][0],m); else if(sum[ch[r][0]]+val[r]<=m) return siz[ch[r][0]]+1+getcnt(ch[r][1],m-sum[ch[r][0]]-val[r]); return siz[ch[r][0]]; } ll ans; void dfs(int x){ int p=x; for(int i=e[x];i;i=ne[i]){ dfs(v[i]); bing(v[i],x); } splay(x,0); int l=getcnt(x,m); ans=max(ans,(ll)l*L[p]); } int main(){ scanf("%d%lld",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%lld%lld",&b[i],&c[i],&L[i]); if(b[i])add(b[i],i); } for(int i=1;i<=n;i++){ siz[i]=1,sum[i]=val[i]=c[i]; } dfs(1); cout<<ans; return 0; }
左偏树现在还不会先学习一下
相关文章推荐
- 关于treap启发式合并的一点脑洞(以bzoj2809为例)
- BZOJ 2733 HNOI2012 永无乡 Treap+启发式合并
- bzoj 2733 Splay 启发式合并,名次树
- USACO 2013open :yinyang(treap+启发式合并)
- BZOJ 2733([HNOI2012]永无乡-Treap启发式合并)
- 洛谷.3224.[HNOI2012]永无乡(Splay启发式合并)
- bzoj 2733 永无乡 Splay 启发式合并
- 2809: [Apio2012]dispatching|splay启发式合并
- 【BZOJ 2733】【HNOI 2012】永无乡 Splay启发式合并
- 【BZOJ2733】永无乡[HNOI2012](splay启发式合并or线段树合并)
- 【Splay】【启发式合并】hdu6133 Army Formations
- 【bzoj2733】【HNOI2012】【永无乡】【treap+启发式合并】
- 【BZOJ 2733】 [HNOI2012]永无乡|Splay启发式合并
- BOZJ2733 [HNOI2012]永无乡(Treap+启发式合并)
- 3545: [ONTAK2010]Peaks 启发式合并treap 离线处理
- 【BZOJ2809】【splay启发式合并】dispatching
- Poj 1741——treap的启发式合并
- BZOJ[2733][HNOI2012]永无乡 Splay启发式合并
- bzoj 3545: [ONTAK2010]Peaks (splay启发式合并)
- BZOJ 2809([Apio2012]dispatching-Splay启发式合并)