题目描述

设T 为一棵有根树,我们做如下的定义:
? 设a和b为T 中的两个不同节点。如果a是b的祖先,那么称“a比b不知道
高明到哪里去了”。
? 设a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定
常数x,那么称“a 与b 谈笑风生”。
给定一棵n个节点的有根树T,节点的编号为1 到 n,根节点为1号节点。你需
要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a;b;c)满足:
1. a、b和 c为 T 中三个不同的点,且 a为p 号节点;
2. a和b 都比 c不知道高明到哪里去了;
3. a和b 谈笑风生。这里谈笑风生中的常数为给定的 k。

输入

第一行含有两个正整数n和q,分别代表有根树的点数与询问的个数。
接下来n - 1行,每行描述一条树上的边。每行含有两个整数u和v,代表在节点u和v之间有一条边。
接下来q行,每行描述一个操作。第i行含有两个整数,分别表示第i个询问的p和k。
1<=P<=N
1<=K<=N
N<=300000
Q<=300000
 

输出

输出 q 行,每行对应一个询问,代表询问的答案。

样例输入

5 3
1 2
1 3
2 4
4 5
2 2
4 1
2 3

样例输出

3
1
3

提示

Hint:边要加双向

  题目大意:给定一个n个节点的有根树,q次询问,每次询问两个数p,k,问满足1、a,b都是c的祖先。2、a编号为p。3、a,b距离<=k。的三元组(a,b,c)有多少个。

  因为a,b都是c的祖先,所以它们其中一个一定是另一个的祖先。a的位置确定了,那就讨论b的位置:当b是a祖先时,直接将a子树大小乘上k和a的深度中小的那个就好了;当a是b祖先时,a子树中与a深度差<=k的点都可以是b,统计这些点的子树和就是答案,也就相当于将每个点的子树大小作为这个点的点权(要将自己刨去)求点权和。如果没有层数限制直接将dfs序架在线段树上区间求和就好了。但有了限制就要用主席树按深度建树,每个深度建一棵线段树,维护这一深度所有点的信息,查询时依旧是查a点子树区间,但因为深度>dep[a]+k的点在主席树中还没有维护信息所以并不影响。

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
ll ans;
int mx;
int n,m;
int p,k;
int x,y;
int num;
int tot;
int cnt;
int s[300010];
int t[300010];
int d[300010];
int to[600010];
int ls[6000010];
int rs[6000010];
ll sum[6000010];
int head[300010];
int next[600010];
int size[300010];
int root[300010];
struct node
{
int dep;
int id;
}a[300010];
bool cmp(node a,node b)
{
return a.dep<b.dep;
}
void add(int x,int y)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void dfs(int x,int fa)
{
num++;
s[x]=num;
a[x].dep=a[fa].dep+1;
d[x]=d[fa]+1;
size[x]=1;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dfs(to[i],x);
size[x]+=size[to[i]];
}
}
t[x]=num;
}
int updata(int pre,int l,int r,int k,int v)
{
int rt=++cnt;
if(l==r)
{
sum[rt]=sum[pre]+v;
return rt;
}
ls[rt]=ls[pre];
rs[rt]=rs[pre];
sum[rt]=sum[pre]+v;
int mid=(l+r)>>1;
if(k<=mid)
{
ls[rt]=updata(ls[pre],l,mid,k,v);
}
else
{
rs[rt]=updata(rs[pre],mid+1,r,k,v);
}
return rt;
}
ll query(int x,int y,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return sum[y]-sum[x];
}
int mid=(l+r)>>1;
if(L>mid)
{
return query(rs[x],rs[y],mid+1,r,L,R);
}
else if(R<=mid)
{
return query(ls[x],ls[y],l,mid,L,R);
}
return query(ls[x],ls[y],l,mid,L,R)+query(rs[x],rs[y],mid+1,r,L,R);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
a[i].id=i;
}
a[n].id=n;
dfs(1,0);
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
mx=max(mx,d[i]);
if(a[i].dep>a[i-1].dep)
{
root[a[i].dep]=root[a[i-1].dep];
}
root[a[i].dep]=updata(root[a[i].dep],1,n,s[a[i].id],size[a[i].id]-1);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&p,&k);
ans=0;
ans+=1ll*min(k,d[p]-1)*(size[p]-1);
ans+=query(root[d[p]],root[min(d[p]+k,mx)],1,n,s[p],t[p]);
printf("%lld\n",ans);
}
}

BZOJ3653谈笑风生——可持久化线段树+dfs序的更多相关文章

  1. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  2. 【CF768G】The Winds of Winter 可持久化线段树 DFS序

    题目大意 给定一棵\(n\)个点的树,对于树上每个结点,将它删去,然后可以将得到的森林中任意一个点与其父亲断开并连接到另一颗树上,对每一个点求出森林中所有树\(size\)最大值的最小值. \(n\l ...

  3. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  4. 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序

    题目大意 ​ Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜 ...

  5. 【bzoj4817】树点涂色 LCT+线段树+dfs序

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  6. S - Query on a tree HDU - 3804 线段树+dfs序

    S - Query on a tree HDU - 3804   离散化+权值线段树 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度. 这个题目和之前写的那个给你一棵 ...

  7. bzoj 3653: 谈笑风生 可持久化线段树

    题目大意 在一棵单位边权的有根树上支持询问: 给定a,k求满足下列条件的有序三元对的个数. a,b,c互不相同 a,b均为c的祖先 a,b树上距离<=k 题解 solution 1 首先我们知道 ...

  8. HDU 5692 线段树+dfs序

    Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  9. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

随机推荐

  1. Android 调用系统相机拍照并获取原图

    第一步:调用相机 Intent getImageByCamera = new Intent( android.provider.MediaStore.ACTION_IMAGE_CAPTURE); St ...

  2. Foreach循环输出索引值

    循环输邮索引值,使用for是没有任何问题: class Bh { public string[] str { get; set; } public void TestFor() { ; i < ...

  3. Luogu P2597 [ZJOI2012]灾难

    一道非常综合的好题然后就莫名其妙地知道了动态LCA的求法 果然是ZJOI的题目,只能说这思路服了 首先我们发现每次操作只会灭绝一种动物,然后我们想一下就知道如果有\(n(n>=2)\)个食物的动 ...

  4. 线程中join()的用法

    Thread中,join()方法的作用是调用线程等待该线程完成后,才能继续用下运行. public static void main(String[] args) throws Interrupted ...

  5. Visual Studio2017 Remote Debugger

    前言 大家在使用vs打包后的文件部署到服务器后,有时候我们需要对线网的后台进行调试.但是它不像在VS中.这个时候我们该怎么调试呢? 微软想到了这一点,他们在 VS 中给我们提供了一个功能: Remot ...

  6. Linux df du 命令

    df 命令 检查磁盘空间占用情况(并不能查看某个目录占用的磁盘大小). 命令格式:df [option] -h 以容易理解的格式(给人看的格式)输出文件系统分区使用情况,例如 10kB.10MB.10 ...

  7. 一台服务器多实例mysql做主从复制

    在一台服务器上开两个端口的mysql(3306.3307),做成主从复制环境 1)安装mysql(安装过程这里就不做过多介绍) 参考:http://www.cnblogs.com/kevingrace ...

  8. Web系统页面打印技术实现与分析

    1 Web页面打印概述应用WEB化,不论对开发商,还是对用户来说,实在是一种很经济的选择,因为基于WEB的应用,客户端的规则很简单,容易学习,容易维护,容易发布.在WEB系统中,打印的确是个烦人的问题 ...

  9. 如何启动Intel VT-X及合理利用搜索

    昨天安装Vmware的时候不幸遇到了Vt-X被禁用的麻烦,上网百度了一下才知道要进入Bois进行设置.说起百度就不得不提到模糊搜索这个概念.这个特性的优点和缺点可谓同等突出,有了模糊搜索大家可以在信息 ...

  10. 美食应用 吃了么 beta 测试报告

    为了更好的测试我们应用的兼容性和性能,我们借助了网上的平台Testin云测和百度MTC平台来测试我们的应用,一下是我们的测试结果. 一.兼容性测试 我们对119台终端机器进行了测试,通过测试的有99台 ...