此后如竟没有炬火 我便是唯一的光|

Day_Dreamer_D

园龄:3年6个月粉丝:3关注:16

2022-10-19 18:52阅读: 60评论: 0推荐: 0

洛谷 P1552 [APIO2012] 派遣 题解

算法:线段树合并,离散化

考虑任意一点 u 为领导者的情况。

显然,选出以 u 为根的子树中薪水 C 最少的 k 个结点(忍者),满足 Cm 的情况下使 k 尽可能大,这样 u 为领导者的最大满意度为 Lu×k

考虑如何高效地求出每个点为领导时可以派遣的忍者的最大数量。

可以想到线段树:我们先离散化,对于每个点 v 求出 Cv 的排名 rkv。把这些都存到一棵以 rk 为下标的线段树上,由于离散化后满足单调性,我们只需要在线段树上二分一下就能得出答案。

那么如何建出这样一棵线段树呢?

不难想到线段树合并:我们对于每一个忍者 w(包含 Master)都开一棵线段树,然后插入 Cw。每次从叶子结点向根结点通过树上二分求出当前点为领导者时能派遣的忍者的最大数两,然后将当前忍者的线段树合并到这个忍者上级的线段树上。

时间复杂度 Ω(nlogn)

/*
* Title: P1552 [APIO2012] 派遣
* Source: Luogu
* URL: https://www.luogu.com.cn/problem/P1552
* Author: Steven_lzx
* Command: -std=c++23 -Wall -fno-ms-extensions
* Date: 2022.10.19
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <utility>
using namespace std;
typedef long long ll;
const int MAXN=100010;
struct Segt
{
int ls,rs,cnt;
ll sum;
}tr[MAXN<<5];
int idx,root[MAXN],n,m,b[MAXN],c[MAXN];
ll l[MAXN],ans;
pair<int,int> t[MAXN];
void update(int p,int l,int r,int k,int c)
{
int mid;
tr[p].cnt++;
tr[p].sum+=c;
if(l==r)
return;
mid=(l+r)>>1;
if(k<mid)
{
if(!tr[p].ls)
tr[p].ls=++idx;
update(tr[p].ls,l,mid,k,c);
}
else
{
if(!tr[p].rs)
tr[p].rs=++idx;
update(tr[p].rs,mid+1,r,k,c);
}
}
int query(int p,int l,int r,int k)
{
int mid;
if(!p)
return 0;
if(l==r)
{
if(tr[p].sum<=k)
return 1;
return 0;
}
mid=(l+r)>>1;
if(tr[tr[p].ls].sum<k)
return tr[tr[p].ls].cnt+query(tr[p].rs,mid+1,r,k-tr[tr[p].ls].sum);
return query(tr[p].ls,l,mid,k);
}
void merge(int &p,int q)
{
if(!p||!q)
{
tr[p+q].cnt=tr[p].cnt+tr[q].cnt;
tr[p+q].sum=tr[p].sum+tr[q].sum;
p+=q;
return;
}
merge(tr[p].ls,tr[q].ls);
merge(tr[p].rs,tr[q].rs);
tr[p].cnt=tr[tr[p].ls].cnt+tr[tr[p].rs].cnt;
tr[p].sum=tr[tr[p].ls].sum+tr[tr[p].rs].sum;
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d%d%lld",b+i,c+i,l+i);
t[i]=make_pair(c[i],i);
}
stable_sort(t+1,t+n+1);
for(int i=1,k;i<=n;i++)
{
root[k=t[i].second]=++idx;
update(root[k],1,n+1,i,c[k]);
}
for(int i=n;i;i--)
{
ans=max(ans,l[i]*query(root[i],1,n+1,m));
if(b[i])
merge(root[b[i]],root[i]);
}
printf("%lld\n",ans);
return 0;
}

本文作者:Day_Dreamer_D's Blog

本文链接:https://www.cnblogs.com/2020gyk080/p/16807381.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Day_Dreamer_D  阅读(60)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起