您的位置:首页 > 其它

[BZOJ 2809][Apio2012]dispatching:可持久化线段树|可并堆

2017-05-04 14:33 459 查看
点击这里查看原题

对于每个忍者被作为管理者的情况,我们需要知道这个忍者管理的忍者中最多能选多少忍者,而要使选的忍者尽可能多,就需要从薪水最低的忍者开始选。

于是可以建立一颗权值线段树,按DFS序将忍者的薪水依次加入,每次求总薪水小于等于k可以选多少忍者。

注意long long,因为这个WA了好几次

/*
User:Small
Language:C++
Problem No.:2809
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=1e5+5;
int n,rt[M],tot,fir[M],cnt,in[M],out[M],dfn,a[M],p[M],id[M],pos[M],ls[M*20],rs[M*20],val[M];
ll sum[M*20],sz[M*20],ans,k,b[M];
struct edge{
int v,nex;
}e[M<<1];
void add(int u,int v){
e[++tot]=(edge){v,fir[u]};
fir[u]=tot;
}
bool cmp(int x,int y){
return a[x]<a[y];
}
void dfs(int u){
in[u]=++dfn;
id[dfn]=pos[u];
val[dfn]=a[u];
for(int i=fir[u];i;i=e[i].nex)
dfs(e[i].v);
out[u]=dfn;
}
void build(int &now,int l,int r,int x,int v){
cnt++;
sum[cnt]=(ll)sum[now]+(ll)v;
sz[cnt]=sz[now]+1;
ls[cnt]=ls[now];
rs[cnt]=rs[now];
now=cnt;
if(l==r) return;
int mid=l+r>>1;
if(x<=mid) build(ls[now],l,mid,x,v);
else build(rs[now],mid+1,r,x,v);
}
ll query(int a,int b,int l,int r,ll k,ll c){
int mid=l+r>>1;
if(l==r){
if(sum[b]-sum[a]<=k&&sum[b]-sum[a]) return c+1;
else return c;
}
ll t=sum[ls[b]]-sum[ls[a]];
if(t>=k) return query(ls[a],ls[b],l,mid,k,c);
else{
return query(rs[a],rs[b],mid+1,r,k-t,c+sz[ls[b]]-sz[ls[a]]);
}
}
int main(){
freopen("data.in","r",stdin);//
scanf("%d%lld",&n,&k);
for(int i=1;i<=n;i++){
int fa;
scanf("%d%d%lld",&fa,&a[i],&b[i]);
if(fa) add(fa,i);
p[i]=i;
}
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;i++) pos[p[i]]=i;
dfs(1);
for(int i=1;i<=n;i++){
rt[i]=rt[i-1];
build(rt[i],1,n,id[i],val[i]);
}
for(int i=1;i<=n;i++){
ll res=query(rt[in[i]-1],rt[out[i]],1,n,k,0);
ans=max(ans,(ll)res*b[i]);
}
printf("%lld\n",ans);
return 0;
}


另一种做法是可并堆,维护最大堆,每当堆中的元素和大于总薪水时删除最大元素。

/*
User:Small
Language:C++
Problem No.:2809
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=1e5+5;
ll n,tot,fir[M],siz[M],rt[M];
ll m,sum[M],b[M],ans,a[M];
struct edge{
ll v,nex;
}e[M<<1];
struct no{
ll l,r;
ll v;
}tr[M<<2];
void add(ll u,ll v){
e[++tot]=(edge){v,fir[u]};
fir[u]=tot;
}
ll merge(ll a,ll b){
if(!a||!b) return a+b;
if(tr[a].v<tr[b].v) swap(a,b);
tr[a].r=merge(tr[a].r,b);
swap(tr[a].l,tr[a].r);
4000
return a;
}
void pop(ll x){
ll root=rt[x];
rt[x]=merge(tr[root].l,tr[root].r);
sum[x]-=tr[root].v;
siz[x]--;
tr[root].l=tr[root].r=tr[root].v=0;
}
void dfs(ll u){
for(ll i=fir[u];i;i=e[i].nex){
ll v=e[i].v;
dfs(v);
sum[u]+=sum[v];
siz[u]+=siz[v];
rt[u]=merge(rt[u],rt[v]);
while(sum[u]>m) pop(u);
}
sum[u]+=a[u];
siz[u]++;
tr[u]=(no){0,0,a[u]};
rt[u]=merge(rt[u],u);
while(sum[u]>m) pop(u);
ans=max(ans,(ll)siz[u]*b[u]);
}
int main(){
freopen("data.in","r",stdin);//
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++){
ll fa;
scanf("%lld%lld%lld",&fa,&a[i],&b[i]);
if(fa) add(fa,i);
}
dfs(1);
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: