题意

给出一棵以1为根节点树,求每个节点的子树中到该节点距离<=l的节点的个数

题解

方法1:倍增+差分数组

首先可以很容易的转化问题,考虑每个节点对哪些节点有贡献

即每次对于一个节点,找到其第l个父亲,这个操作可以用倍增在logn时间内完成

找到后将x-y这一段区间都加1,很容易想到用差分数组维护

方法2:主席树

考虑节点x和节点x的子树中的一个节点y,记点x到根节点的距离为dis[x]

若dis[y]-dis[x]<=l则满足条件

将不等式变形可得dis[y]<=dis[x]+l

即对每个点以dis[ ]为权值插入树中,查询时查找比dis[x]+l小的节点个数

这时很容易想到主席树,第一维对dis[x](维护的前缀也就是查询的答案),第二维对节点编号

又由于先决条件是节点y是在x的子树中的,所以我们应弄出一个dfs序

对于每一个节点,其子树即num[x]-----子树中num[y]的最大值

其次,插入时为避免对之后的节点造成影响,应将dis[]从小到大进行插入

注意到dis数据范围较大考虑对其离散化

还有就是,主席树的题目空间往往不能浪费太多

方法3:左偏树

可以考虑,对于节点x的子树中的一个节点

若x与这个节点的距离>l,那么x的父亲与这个节点的距离也一定>l

所以可以考虑用左偏树来维护

对于每个节点x,枚举它的儿子y,维护一个大根堆

另外,两个点之间的距离可以用dis[1,y]-dis[1,x]表示

**没仔细看题数据是longlong啊。。

代码

方法1:倍增+差分数组

方法2:主席树

uses math;
type re=record
a,b,c,num:int64;
end;
type ree=record
h,t,x:longint;
end;
var
i,j:longint;
now,m,n,c,d,k,l,o,ans,x,tmp:int64;
a,dis:array[..]of re;
f:array[..]of boolean;
num,fa,head,q:array[..]of int64;
p:array[..]of ree;
procedure arr(x,y,z:int64);
begin
inc(l);
a[l].a:=head[x];
a[l].b:=y;
a[l].c:=z;
head[x]:=l;
end;
function dfs(x,y:int64):int64;
var u,v:longint;
begin
f[x]:=false; dis[x].a:=y; dis[x].b:=x;
inc(now); dis[x].num:=now;
u:=head[x]; dfs:=now;
while u<> do
begin
v:=a[u].b;
if f[v] then dfs:=max(dfs,dfs(v,y+a[u].c));
u:=a[u].a;
end;
dis[x].c:=dfs;
end;
procedure swap(var x,y:re);
var tmp:re;
begin
tmp:=x; x:=y; y:=tmp;
end;
procedure qsort(h,t:int64);
var i,j,mid:int64;
begin
i:=h; j:=t; mid:=dis[(h+t) div ].a;
repeat
while dis[i].a<mid do inc(i);
while dis[j].a>mid do dec(j);
if i<=j then
begin
swap(dis[i],dis[j]);
inc(i); dec(j);
end;
until i>j;
if i<t then qsort(i,t);
if h<j then qsort(h,j);
end;
procedure build(x,h,t:int64);
var mid:int64;
begin
p[x].h:=x*; p[x].t:=x*+; now:=max(now,x*+);
if h=t then exit;
mid:=(h+t) div ;
build(x*,h,mid); build(x*+,mid+,t);
end;
function find(x:int64):int64;
var h,t,mid:int64;
begin
h:=; t:=n;
while h<t do
begin
mid:=(h+t) div +;
if dis[mid].a<=x then h:=mid else t:=mid-;
end;
exit(h);
end;
procedure insert(pre,x,h,t:int64);
var tmp,mid:longint;
begin
inc(now); p[now]:=p[pre]; inc(p[now].x); tmp:=now;
if h=t then exit;
mid:=(h+t) div ;
if (x<=mid) then
begin
insert(p[now].h,x,h,mid);
p[tmp].h:=tmp+;
end else
begin
insert(p[now].t,x,mid+,t);
p[tmp].t:=tmp+;
end;
end;
function query(x,h1,t1,h,t:int64):int64;
var mid:int64;
begin
if (h>t1) or (t<h1) then exit();
if (h<=h1) and (t1<=t) then exit(p[x].x);
mid:=(h1+t1) div ;
exit(query(p[x].h,h1,mid,h,t)+query(p[x].t,mid+,t1,h,t));
end;
begin
readln(n,k); fillchar(f,sizeof(f),true);
for i:= to n- do
begin
read(c,d); arr(i+,c,d); arr(c,i+,d);
end;
dfs(,);
qsort(,n); o:=;
for i:= to n do
begin
if (i=) or (dis[i].a<>dis[i-].a) then
inc(o);
num[i]:=o;
end;
now:=; build(,,n);
fa[]:=;
for i:= to n do
begin
if (i<>) and (num[i]=num[i-]) then
begin
tmp:=now;
insert(fa[num[i]],dis[i].num,,n);
fa[num[i]]:=tmp+;
end
else
begin
fa[num[i]]:=now+;
insert(fa[num[i]-],dis[i].num,,n);
end;
end;
for i:= to n do
begin
x:=find(dis[i].a+k);
ans:=query(fa[num[x]],,n,dis[i].num,dis[i].c);
q[dis[i].b]:=ans;
end;
for i:= to n do writeln(q[i]);
end.

方法3:左偏树

type re=record
a,b,c:int64;
end;
var
i,j:longint;
m,n,ans,l,c,d:int64;
k:int64;
f:array[..]of boolean;
a:array[..]of re;
dis,left1,right1,fa,cnt,ll,head,vv,num:array[..]of int64;
procedure arr(x,y,z:int64);
begin
inc(l);
a[l].a:=head[x];
a[l].b:=y;
a[l].c:=z;
head[x]:=l;
end;
function getfa(x:int64):int64;
begin
while (fa[x]<>) do x:=fa[x];
exit(x);
end;
procedure swap(var x,y:int64);
var tmp:int64;
begin
tmp:=x; x:=y; y:=tmp;
end;
function merge(x,y:int64):int64;
var tmp:int64;
begin
if (x=) or (y=) then exit(x+y);
if (dis[x]<dis[y]) then swap(x,y);
right1[x]:=merge(right1[x],y);
fa[right1[x]]:=x;
if (ll[left1[x]]<ll[right1[x]]) then swap(left1[x],right1[x]);
ll[x]:=ll[right1[x]]+; cnt[x]:=cnt[left1[x]]+cnt[right1[x]]+;
exit(x);
end;
function delete(x:int64):int64;
var tmp:int64;
begin
fa[left1[x]]:=; fa[right1[x]]:=;
if left1[x]<> then tmp:=left1[x] else tmp:=right1[x];
merge(left1[x],right1[x]);
exit(getfa(tmp));
end;
procedure dfs(x,y:int64);
var u,v,c,d,goal,ans,z:int64;
begin
ans:=; f[x]:=false; dis[x]:=y;
u:=head[x];
while u<> do
begin
v:=a[u].b;
if f[v] then
begin
dfs(v,y+a[u].c);
c:=getfa(v); goal:=y+k;
while (c<>) and (dis[c]>goal) do
begin
c:=delete(c);
end;
if c<> then
begin
ans:=ans+cnt[c];
z:=getfa(x);
merge(z,c);
end;
end;
u:=a[u].a;
end;
if k>= then vv[x]:=ans+ else vv[x]:=ans;
end;
begin
readln(n,k);
if k< then writeln('');
for i:= to n- do
begin
read(c,d); arr(i+,c,d); arr(c,i+,d);
end;
for i:= to n do cnt[i]:=;
fillchar(f,sizeof(f),true);
dfs(,);
for i:= to n do writeln(vv[i]);
end.

[BZOJ3011][Usaco2012 Dec]Running Away From the Barn的更多相关文章

  1. bzoj3011 [Usaco2012 Dec]Running Away From the Barn 左偏树

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3011 题解 复习一下左偏树板子. 看完题目就知道是左偏树了. 结果这个板子还调了好久. 大概已 ...

  2. 【BZOJ3011】[Usaco2012 Dec]Running Away From the Barn 可并堆

    [BZOJ3011][Usaco2012 Dec]Running Away From the Barn Description It's milking time at Farmer John's f ...

  3. BZOJ 3011: [Usaco2012 Dec]Running Away From the Barn( dfs序 + 主席树 )

    子树操作, dfs序即可.然后计算<=L就直接在可持久化线段树上查询 -------------------------------------------------------------- ...

  4. BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆

    BZOJ_3011_[Usaco2012 Dec]Running Away From the Barn _可并堆 Description 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于l的 ...

  5. [Usaco2012 Dec]Running Away From the Barn

    题目描述 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于l的点有多少个. 输入格式 Line 1: 2 integers, N and L (1 <= N <= 200,0 ...

  6. BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序

    BZOJ_3012_[Usaco2012 Dec]First!_trie树+拓扑排序 题意: 给定n个总长不超过m的互不相同的字符串,现在你可以任意指定字符之间的大小关系.问有多少个串可能成为字典序最 ...

  7. 【BZOJ3012】[Usaco2012 Dec]First! Trie树+拓补排序

    [BZOJ3012][Usaco2012 Dec]First! Description Bessie has been playing with strings again. She found th ...

  8. [USACO 12DEC]Running Away From the Barn

    Description It's milking time at Farmer John's farm, but the cows have all run away! Farmer John nee ...

  9. USACO Running Away From the Barn /// 可并堆 左偏树维护大顶堆

    题目大意: 给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于m的点有多少个 左偏树 https://blog.csdn.net/pengwill97/article/details/82 ...

随机推荐

  1. Entity framework中LINQ的使用

    一.linq和ef的差别 我们做项目时,难免会遇到用的不知道是啥,及把linq和EF搞混了.今天我带领大家梳理下思路,首先说linq查询,然后介绍EF查询 1.linq查询 当我们使用linq查询时, ...

  2. Android Day2

    紧接前一篇日记: 2.增加文本域 在<LinearLayout>中增加<EditText>元素,无格式设置的时候如下. <EditText android:id=&quo ...

  3. 020_iPhone救命稻草

    一.如何对iPhone强制恢复出厂设置 1.在"通用"->"设置"->"还原全部设置",但是我的不知道为啥除了设置完开机密码后, ...

  4. $Django 路飞之课程下的分类,用户登陆成功前端存cookie,

    一 课程分类显示 宗旨:总的再次过滤 二 Cookie # export default new Vuex.Store({ state: { name:'', token:'', }, mutatio ...

  5. 缓存系列之三:redis安装及基本数据类型命令使用

    一:Redis是一个开源的key-value存储系统.与Memcached类似,Redis将大部分数据存储在内存中,支持的数据类型包括:字符串.哈希表.链表.集合.有序集合以及基于这些数据类型的相关操 ...

  6. 持续集成之②:整合jenkins与代码质量管理平台Sonar并实现构建失败邮件通知

    持续集成之②:整合jenkins与代码质量管理平台Sonar并实现构建失败邮件通知 一:Sonar是什么?Sonar 是一个用于代码质量管理的开放平台,通过插件机制,Sonar 可以集成不同的测试工具 ...

  7. 【算法】二分查找法&大O表示法

    二分查找 基本概念 二分查找是一种算法,其输入是一个有序的元素列表.如果要查找的元素包含在列表中,二分查找返回其位置:否则返回null. 使用二分查找时,每次都排除一半的数字 对于包含n个元素的列表, ...

  8. 6)django-示例(fbv)

    FBV(function base view),即一个url对应views.py一个函数 示例演示如下 1)FBV如何使用 2)渲染页面,并返回字典数据 3)字典数据页面如何访问 1)url.py f ...

  9. destoon使用

    使用小计 1.判断是否是手机端 {$DT_TOUCH}模板中使用 2.判断句 {if}  {/if} 3.表单管理 扩展功能-----表单管理:添加表单---->管理表单选项------> ...

  10. Confluence 6 新 Confluence 安装配置一个数据源连接

    如果在你的 Tomcat 中配置了数据源,并且Confluence 设置指南在安装的时候检测到这个配置的时候,配置数据源的选项将会提供给你进行配置.入股你希望使用数据源,请参考下面的配置. 1. 停止 ...