题目是中文的就不给题意了~
题解: 忍者组织可以看成一棵树,根是master,题意其实就是要在找到的点的权值和不超过给定的M的情况下,在一棵子树上找尽量多的点使得点的数量×子树的根的L最大,求这个最大值。
DFS,对于一个结点,先在他孩子的子树找点的最大值,再将他的孩子找到的点合并,如果权值和超过了M,就删掉最大的点,不断操作直到和小于M,计算这棵子树的最大值。对于合并和查找操作用左偏树(可并堆)维护
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<vector>
#include<string>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL maxn = 210000;
struct edge
{
LL y,next;
}a[maxn<<1]; LL len,first[maxn];
void insert( LL x,LL y )
{
len++;
a[len].y = y;
a[len].next = first[x]; first[x] = len;
}
struct tree
{
LL lc,rc,c,dist;
}tr[maxn]; LL n,m;
LL fa[maxn],s[maxn],c[maxn],siz[maxn];
LL ans = 0;
LL find_( LL x )
{
if( fa[x] == x ) return x;
return fa[x] = find_( fa[x] );
}
LL merge( LL x,LL y )
{
if( !x ) return y;
if( !y ) return x;
if( tr[x].c < tr[y].c ) swap( x,y );
LL k = merge( tr[x].rc,y );
tr[x].rc = k; fa[k] = x;
if( tr[tr[x].lc].dist < tr[tr[x].rc].dist ) swap( tr[x].lc,tr[x].rc );
tr[x].dist = tr[tr[x].rc].dist+1;
return x;
}
void dfs( LL x,LL f )
{
siz[x] = 1;
c[x] = tr[x].c;
for( LL k=first[x];k;k=a[k].next )
{
LL y = a[k].y;
if( y != f )
{
dfs( y,x );
merge( find_( x ),find_( y ) );
c[x] += c[y];
siz[x] += siz[y];
}
}
while( c[x] > m )
{
LL f1 = find_( x );
c[x] -= tr[f1].c;
siz[x] --;
LL k = merge( tr[f1].lc,tr[f1].rc );
fa[f1] = k;
fa[k] = k;
}
ans = max( ans,siz[x]*s[x] );
}
int main()
{
LL x,t;
memset( first,0,sizeof first ); len = 0;
scanf("%lld%lld",&n,&m);
for( LL i=1;i<=n;i++ )
{
fa[i] = i;
tr[i].dist = tr[i].lc = tr[i].rc = 0;
scanf("%lld%lld%lld",&x,&tr[i].c,&s[i]);
if( i != 1 )
{
insert( i,x );
insert( x,i );
}
}
dfs( 1,0 );
printf("%lld\n",ans);
return 0;
}