题意

给出一棵以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. Android应用内嵌unity3d游戏项目

    在一个现有的Android项目中嵌入unity3d项目 1.将unity3d项目导出android工程 2.将第一步导出的Android工程中assets文件夹和libs文件夹下的所有内容复制到And ...

  2. canvas - 简单画板

    截图: Demo:Demo 上代码:. <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  3. ansible笔记(1)在centos中安装ansible

    ansible笔记():ansible的基本概念 一些基础概念 ansible是什么? 它是一个"配置管理工具",它是一个"自动化运维工具",如果你没有使用过任 ...

  4. Golang 优化之路——bitset

    写在前面 开发过程中会经常处理集合这种数据结构,简单点的处理方法都是使用内置的map实现.但是如果要应对大量数据,例如,存放大量电话号码,使用map占用内存大的问题就会凸显出来.内存占用高又会带来一些 ...

  5. C和C++相互调用

    在项目中融合C和C++有时是不可避免的,在调用对方的功能函数的时候,或许会出现这样那样的问题.近来在主程序是C语言,而调用C++功能函数的时候,C++的*.h头文件都能找到,功能函数也都定义了,最重要 ...

  6. MR1和MR2(Yarn)工作原理流程

    一.Mapreduce1 图1  MR1工作原理图 工作流程主要分为以下6个步骤: 1 作业的提交 1)客户端向jobtracker请求一个新的作业ID(通过JobTracker的getNewJobI ...

  7. linux学习之uniq

    uniq最经常用的是统计次数,通常先排序,然后uniq  -c cat a.txt |sort -nr |uniq -c

  8. Hive学习01-基础常见问题

      理论: 什么是hive: 1. Hive旨在实现轻松的数据汇总,即时查询和分析大量数据. 2. 它提供了SQL,使用户可以轻松地进行临时查询,汇总和数据分析. 3. Hive可以使用用户定义函数( ...

  9. Confluence 6 升级 Confluence 使用数据源

    如果你对 Confluence 进行升级(手动或者使用安装器),你需要: 停止 Confluence (如果你已经尝试开始启动). 拷贝你的数据库驱动到 <installation-direct ...

  10. Confluence 6 站点高级自定义

    你可以继续编辑的全局布局文件来继续更新你的主面板.请查看 Customizing the Confluence Dashboard 页面来获得更多有关的信息.你需要具有一些基本的Velocity 知识 ...