题意

给出一棵以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. Server-side activities have been updated. You need to restart SharePoint Designer to use the updated version of activities

    一,环境: SharePoint Online Win10 + SharePoint Designer 2013 错误描述: 使用SPD3013打开SPO站点,然后编辑已有工作流(2013),报错: ...

  2. page.isvalid

    背景 看到这个标题,想了半天,为啥用的.应该是当初前台要动态增加行这个事情,当初用.net真是用傻了,竟然对html.aspx原理不大清楚,对于html也想着后台生成.真是弱智啊.谈到这里,想到c#这 ...

  3. nginx中Geoip_module模块的使用

    nginx中Geoip_module模块的使用 .安装模块,nginx也是通过yum安装 yum install nginx-module-geoip -y # 可以看到模块的链接库文件 [root@ ...

  4. 在eclipse中安装svn插件

    1.下载SVN插件 下载地址:https://github.com/subclipse/subclipse 点击"Files" 2.安装 在eclipse 中点击菜单"w ...

  5. Android中验证输入是否为汉字、手机号及邮箱

    1,验证是否为汉字 Code// 验证昵称 private boolean verifyNickname() { String nickname = edt_username.getText().to ...

  6. 正版phpstorm,webstorm,goland(Jetbrains系列都可以)免费激活步骤(图文详解)(亲测有效)

    1 前言 Jetbrains系列都可以,包括webstrom,phpstorm,goland等. 附加其它方案如下: webstrom(注册机) goland(破解补丁) 2 步骤 1. 可以先试用, ...

  7. 远程连接阿里云的mysql数据库

    第一步 由于mysql版本问题 先尝试打开 sudo vim /etc/mysql/my.cnf 如空,再尝试打开 sudo vim /etc/mysql/mysql.conf.d/mysqld.cn ...

  8. Linux 的 OOM 终结者(Out Of Memory killer)

    现在是早晨6点钟.已经醒来的我正在总结到底是什么事情使得我的起床闹铃提前了这么多.故事刚开始的时候,手机铃声恰好停止.又困又烦躁的我看了下手机,看看是不是我自己疯了把闹钟调得这么早,居然是早晨5点.然 ...

  9. 配置nginx php上传大文件

    配置nginx php上传大文件: 1. 修改PHP配置文件中的三项:vim /usr/local/php/etc/php.ini 1.file_uploads 设为On,允许通过HTTP上传文件 2 ...

  10. vue v-show绑定

    在Vue中使用v-show指令来选择性的显示内容.它的属性值可以是布尔值.属性名称以及函数名称.如果使用函数来控制的话,无论函数内容如何运算判断,最终返回布尔值true或者false就可以了 < ...