题目大意:给定一棵有根树,求以每个点为根的子树中有多少点到它的距离不超过l
第一眼是可并堆- - 于是怒写- - 管它正解是啥- -
从下到上维护可并大根堆 键值是该点到当前根节点的距离 一旦堆顶剪枝大于l就弹顶
时间复杂度O(nlogn)
什么?你说将整个堆都加上一个值?
打标记不就好了- - 毫无疑问可并堆是可以打标记的- -
此外我的随机堆写if(flag^=1)就T写if(rand()&1)就秒过是什么鬼- -
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
struct edge{
int to,next;
long long f;
}table[M<<1];
int head[M],tot;
int n,ans[M];
long long l;
void Add(int x,int y,long long z)
{
table[++tot].to=y;
table[tot].f=z;
table[tot].next=head[x];
head[x]=tot;
}
namespace Random_Heap{
struct abcd{
abcd *ls,*rs;
long long val,mark;
int size;
abcd():ls(0x0),rs(0x0),val(0),mark(0),size(1) {}
void Add(long long x)
{
val+=x;
mark+=x;
}
void Push_Down()
{
if(mark)
{
if(ls) ls->Add(mark);
if(rs) rs->Add(mark);
mark=0;
}
}
void Push_Up()
{
size=1;
if(ls) size+=ls->size;
if(rs) size+=rs->size;
}
}*heap[M];
abcd* Merge(abcd *x,abcd *y)
{
if(!x) return y;
if(!y) return x;
if(x->val<y->val)
swap(x,y);
x->Push_Down();
if(rand()&1)
x->rs=Merge(x->rs,y);
else
x->ls=Merge(x->ls,y);
x->Push_Up();
return x;
}
void Pop(abcd *&x)
{
x->Push_Down();
x=Merge(x->ls,x->rs);
}
}
void Tree_DP(int x)
{
using namespace Random_Heap;
int i;
heap[x]=new abcd;
for(i=head[x];i;i=table[i].next)
{
Tree_DP(table[i].to);
heap[table[i].to]->Add(table[i].f);
while( heap[table[i].to] && heap[table[i].to]->val>l )
Pop(heap[table[i].to]);
heap[x]=Merge(heap[x],heap[table[i].to]);
}
ans[x]=heap[x]->size;
}
int main()
{
int i,x;
long long y;
cin>>n>>l;
for(i=2;i<=n;i++)
{
scanf("%d%lld",&x,&y);
Add(x,i,y);
}
Tree_DP(1);
for(i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}