您的位置:首页 > 其它

【bzoj2809】[Apio2012]dispatching

2017-01-12 18:11 465 查看
= =这道题调了好多遍才过。

其实分析一下这道题还是蛮简单的。

首先建图的时候我们把每个忍者作为一个点,我们可以发现,每个忍者的入度都为1(除了master),所以我们对其进行dfs,可以保证每个点只被遍历到一遍。

其次,这道题是可以贪心的,一方面这道题的结果为忍者个数*领导力,所以我们可以选择薪酬尽量小的忍者,另一方面,在dfs树中处于上端的忍者可以选择所有下端的忍者,也就是说,我们可以维护一个大根堆,堆中含有下层搜索树中的所有点,每次插入此时正在遍历的点,然后弹出权值最大的点直到堆中所有权值之和小于总薪酬。

如上分析,所以应该用一个可并堆,于是使用左偏树,跑的很快,交了很多遍是因为一直wa发现最后自己的merge写错了QAQ.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;
const int N=100010;
int tot=0,cnt=0,head
,c
,root
;
int n,m,l
;
long long ans=0,sum
,size
;
struct edge{
int u,v,next;
}e[100010];
int add(int u,int v){
e[++tot].u=u;
e[tot].v=v;
e[tot].next=head[u];
head[u]=tot;
}
struct Lefttree{
int dis
,rc
,lc
,v
;
int merge(int x,int y)
{
if (!x||!y)return x+y;
int tmp;
if (v[x]<v[y])tmp=x,x=y,y=tmp;
rc[x]=merge(rc[x],y);
if (!lc[x]||dis[rc[x]]>dis[lc[x]])tmp=rc[x],rc[x]=lc[x],lc[x]=tmp;
if(rc[x])dis[x]=dis[rc[x]]+1;
else dis[x]=0;
return x;
}
void pop(int &x){
x=merge(lc[x],rc[x]);
}
int top(int x){
return v[x];
}
}lt;
inline int F(){
register int aa,bb;register char ch;
while(ch=getchar(),ch!='-'&&(ch>'9'||ch<'0'));ch=='-'?aa=bb=0:(aa=ch-'0',bb=1);
while(ch=getchar(),ch>='0'&&ch<='9')aa=(aa<<3)+(aa<<1)+ch-'0';return bb?aa:-aa;
}
void dfs(int u)
{
size[u]=1;sum[u]=c[u];
root[u]=++cnt;lt.v[cnt]=c[u];
for (int i=head[u];i;i=e[i].next)
{
dfs(e[i].v);
size[u]+=size[e[i].v];
root[u]=lt.merge(root[u],root[e[i].v]);
sum[u]+=sum[e[i].v];
}
while(sum[u]>m&&size[u]>0)
{
sum[u]-=lt.top(root[u]);
lt.pop(root[u]);size[u]--;
}
ans=max(ans,size[u]*l[u]*1ll);
}
int main()
{
memset(sum,0,sizeof(sum));
n=F();m=F();int v;
for (int i=1;i<=n;i++)
{
v=F(),c[i]=F(),l[i]=F();
add(v,i);
}
dfs(1);
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: