传送门1
传送门2
写在前面:祝自己生日快乐
思路:
题意简述为在一棵节点有特征值有费用的有根树上选定一个节点,在它的子树上找任意个节点使其总费用不超过m,要求权值最大(权值=该节点的特征值*选择的节点数)
比较暴力的思路是枚举每一个节点,从它的子树上依次选取费用从小到大的节点,直到超过费用或子树上全部节点都被选了,求出最大值即可,时间复杂度 O(n2)
将该思路精进一下,我们发现只要维护每个子树上的点费用从小到大,再加一个前缀和之类的东西,快速判断某一区间费用和是否超过费用即可就可以了
这就用到了主席树
这里的主席树不再是求区间第k大,因为它是权值线段树,节点即是费用(离散化后),所以在主席树上维护下前缀和,每次查询时判断[l,mid]是否超过限制,如果没有就加上左区间的点数,并到[mid+1,r]上去找,不然就继续到[l,mid]上找,每次查询的复杂度为 O(nlogn)
注意:
1.维护树上区间使用dfs序重新编号
2.离散化后的值仅是为了在主席树上使其有序,建树和查询时要用到的除了size还有费用前缀和sum
代码:
#include<bits/stdc++.h>
#define M 100004
#define LL long long
using namespace std;
int n,m,cnt,root,tot;
LL ans;
int fa[M],b[2][M],c[M],ID[M],first[M],Ls[M],Rs[M];//b[0]为离散化前的费用,b[1]为离散化后的费用,ID[i]记录离散化后为i的原费用
struct Chairman_tree
{
int ch[2],siz;
LL sum;
}a[M<<5];
struct disc
{
int id,data;
bool operator <(const disc other)const
{
return data<other.data;
}
}d[M];
struct edge
{
int u,v,next;
void add(int x,int y)
{
u=x;v=y;
next=first[x];
first[x]=tot;
}
}e[M];
int in()
{
char ch=getchar();int t=0;
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) t=(t<<3)+(t<<1)+ch-48,ch=getchar();
return t;
}
void dfs(int x)
{
Ls[x]=++cnt;
d[cnt].id=x;d[cnt].data=b[1][x];
for (int i=first[x];i;i=e[i].next)
dfs(e[i].v);
Rs[x]=cnt;
}
void build(int now,int L,int R,int rt,int val)
{
a[rt].siz=a[now].siz+1;
a[rt].sum=a[now].sum+ID[val];
if (L==R) return;
int mid=(L+R)>>1;
if (val<=mid)
a[rt].ch[1]=a[now].ch[1],
a[rt].ch[0]=++cnt,
build(a[now].ch[0],L,mid,a[rt].ch[0],val);
else
a[rt].ch[0]=a[now].ch[0],
a[rt].ch[1]=++cnt,
build(a[now].ch[1],mid+1,R,a[rt].ch[1],val);
}
int get(int begin,int end,int L,int R,LL val)
{
if (begin==end)
if (ID[end]<=val) return a[R].siz-a[L].siz;
else return 0;
int mid=(begin+end)>>1;
LL t=a[a[R].ch[0]].sum-a[a[L].ch[0]].sum;
if (val>t)
return a[a[R].ch[0]].siz-a[a[L].ch[0]].siz+get(mid+1,end,a[L].ch[1],a[R].ch[1],val-t);
else return get(begin,mid,a[L].ch[0],a[R].ch[0],val);
}
main()
{
n=in();m=in();
for (int i=1;i<=n;i++)
{
fa[i]=in();
if (fa[i]) e[++tot].add(fa[i],i);
else root=i;
b[0][i]=in(),
d[i].id=i,d[i].data=b[0][i];
c[i]=in();
}
sort(d+1,d+n+1);
for (int i=1;i<=n;i++)
b[1][d[i].id]=i,
ID[i]=b[0][d[i].id];
dfs(root);
cnt++;
for (int i=1;i<=n;i++) build(i,1,n,i+1,d[i].data);
for (int i=1;i<=n;i++)
ans=max(ans,(LL)c[i]*get(1,n,Ls[i],Rs[i]+1,m));
printf("%lld",ans);
}