【刷题】BZOJ 3653 谈笑风生
Description
设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)满足:
a、b和 c为 T 中三个不同的点,且 a为p 号节点;
a和b 都比 c不知道高明到哪里去了;
a和b 谈笑风生。这里谈笑风生中的常数为给定的 k。
Input
第一行含有两个正整数n和q,分别代表有根树的点数与询问的个数。
接下来n - 1行,每行描述一条树上的边。每行含有两个整数u和v,代表在节点u和v之间有一条边。
接下来q行,每行描述一个操作。第i行含有两个整数,分别表示第i个询问的p和k。
1<=P<=N
1<=K<=N
N<=300000
Q<=300000
Output
输出 q 行,每行对应一个询问,代表询问的答案。
Sample Input
5 3
1 2
1 3
2 4
4 5
2 2
4 1
2 3
Sample Output
3
1
3
HINT
Hint:边要加双向
Solution
显然存在两种情况:
- \(a\) 在 \(b\) 下面,这样就是 \(a\) 的除去自己的子树大小乘上 \(k\) 和 \(a\) 深度的值小者。这个很显然嘛。
- \(a\) 在 \(b\) 上面,这种情况,设计dp,\(f[i][j]\) 代表第 \(i\) 个点,其往下距离 \(i\) 长度 \(j\) 的点的除自己之外的子树大小和。那么答案就是 \(\sum_{i=1}^kf[p][i]\) 。发现这个dp与深度有关,所以长链剖分优化。然后因为还要求一个前缀和,所以要在dp时处理好。因为这个长链剖分dp只有加没有删,所以可以维护后缀和,答案差分算就好了。
综合上面两种情况,先把所有的询问挂在点上,然后dp统计答案
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define REP(a,b,c) for(register int a=(b),a##end=(c);a<=a##end;++a)
#define DEP(a,b,c) for(register int a=(b),a##end=(c);a>=a##end;--a)
const int MAXN=300000+10;
int n,q,e,beg[MAXN],nex[MAXN<<1],to[MAXN<<1],dep[MAXN],size[MAXN],hson[MAXN],Mxdep[MAXN],top[MAXN],cnt,id[MAXN];
ll ans[MAXN];
std::deque<ll> f[MAXN];
std::vector< std::pair<int,int> > V[MAXN];
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
}
inline void dfs1(int x,int p)
{
dep[x]=dep[p]+1;Mxdep[x]=dep[x];hson[x]=x;
for(register int i=beg[x];i;i=nex[i])
if(to[i]==p)continue;
else
{
dfs1(to[i],x);
if(Mxdep[to[i]]>Mxdep[x])hson[x]=to[i],Mxdep[x]=Mxdep[to[i]];
}
}
inline void dfs2(int x,int p,int tp)
{
top[x]=tp;
if(hson[x]!=x)dfs2(hson[x],x,tp);
for(register int i=beg[x];i;i=nex[i])
if(to[i]==p||to[i]==hson[x])continue;
else dfs2(to[i],x,to[i]);
}
#define ft first
#define sd second
inline void dfs(int x,int p)
{
if(hson[x]==x)
{
id[x]=++cnt;
f[id[x]].resize(dep[x]-dep[top[x]]);
return ;
}
dfs(hson[x],x);
id[x]=id[hson[x]];size[x]+=size[hson[x]]+1;
ll now=size[hson[x]];
f[id[x]].push_front(0);
for(register int i=beg[x];i;i=nex[i])
if(to[i]==p||to[i]==hson[x])continue;
else
{
dfs(to[i],x);
now+=size[to[i]];size[x]+=size[to[i]]+1;
REP(j,1,Mxdep[to[i]]-dep[to[i]])f[id[x]][j]+=f[id[to[i]]][j-1];
}
f[id[x]][0]=f[id[x]][1]+now;
REP(i,0,V[x].size()-1)
{
std::pair<int,int> pr=V[x][i];
int ps=min(Mxdep[x]-dep[x],pr.sd-1);
ans[pr.ft]=1ll*min(dep[x]-1,pr.sd)*size[x]+f[id[x]][0]-f[id[x]][ps+1];
}
}
#undef ft
#undef sd
int main()
{
read(n);read(q);
REP(i,1,n-1)
{
int u,v;read(u);read(v);
insert(u,v);insert(v,u);
}
REP(i,1,q)
{
int p,k;read(p);read(k);
V[p].push_back(std::make_pair(i,k));
}
dfs1(1,0);dfs2(1,0,1);dfs(1,0);
REP(i,1,q)printf("%lld\n",ans[i]);
return 0;
}
【刷题】BZOJ 3653 谈笑风生的更多相关文章
- 主席树 || 可持久化线段树 || BZOJ 3653: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生
题面:P3899 [湖南集训]谈笑风生 题解: 我很喜欢这道题. 因为A是给定的,所以实质是求二元组的个数.我们以A(即给定的P)作为基点寻找答案,那么情况分两类.一种是B为A的父亲,另一种是A为B的 ...
- BZOJ 3653: 谈笑风生(离线, 长链剖分, 后缀和)
题意 给你一颗有 \(n\) 个点并且以 \(1\) 为根的树.共有 \(q\) 次询问,每次询问两个参数 \(p, k\) .询问有多少对点 \((p, a, b)\) 满足 \(p,a,b\) 为 ...
- BZOJ.3653.谈笑风生(长链剖分/线段树合并/树状数组)
BZOJ 洛谷 \(Description\) 给定一棵树,每次询问给定\(p,k\),求满足\(p,a\)都是\(b\)的祖先,且\(p,a\)距离不超过\(k\)的三元组\(p,a,b\)个数. ...
- bzoj 3653 谈笑风生——主席树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3653 原来一直想怎么线段树合并.可是不会把角标挪一位. 查询的其实是子树内一段深度的点的 s ...
- bzoj 3653 谈笑风生 —— 主席树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3653 对于一个 (a,b,c),分成 b 是 a 的祖先和 b 在 a 子树里两部分: 第一 ...
- BZOJ 3653 谈笑风生
ORZ blutrex...... 主席树. #include<iostream> #include<cstdio> #include<cstring> #incl ...
- BZOJ 3653: 谈笑风生(DFS序+可持久化线段树)
首先嘛,还是太弱了,想了好久QAQ 然后,这道题么,明显就是求sigma(size[x]) (x是y的儿子且层树小于k) 然后就可以发现:把前n个节点按深度建可持久化线段树,就能用前缀和维护了 其实不 ...
- bzoj 3653: 谈笑风生 可持久化线段树
题目大意 在一棵单位边权的有根树上支持询问: 给定a,k求满足下列条件的有序三元对的个数. a,b,c互不相同 a,b均为c的祖先 a,b树上距离<=k 题解 solution 1 首先我们知道 ...
- bzoj 3653: 谈笑风生【dfs序+主席树】
考虑b的两种情况,一种是p的祖先,这种点有min(k,de[p]-1)个,然后每个这种b都有si[p]-1个c点可选: 另一种是p的子孙,要求是在p的子树内且deep在de[p]+1~de[p]+k之 ...
随机推荐
- solr服务器搭建与Tomact整合及使用
一:solr服务器的搭建 1:搭建全新的为solr专用的solr服务器: 在自己电脑上搭建两台Tomact服务器,一台仍为应用服务器,一台作为solr服务器,应用服务器按照正常Tomact服务器搭建即 ...
- 20155331 Exp3 免杀原理与实践
20155331 Exp3 免杀原理与实践 基础问题回答 杀软是如何检测出恶意代码的? 1.基于特征码的检测,2.启发式恶意软件检测,3.基于行为的恶意软件检测. 免杀是做什么? 让病毒不被杀毒软件杀 ...
- 【php增删改查实例】 第三节 - mysql 建表
这一节,来给数据库中添加一些测试数据. 登陆mysql: 找到%xampp%\mysql\bin 目录, 在此处打开命令窗口,用root用户登陆mysql 用户表建表sql: CREATE TABLE ...
- python 回溯法 子集树模板 系列 —— 18、马踏棋盘
问题 将马放到国际象棋的8*8棋盘board上的某个方格中,马按走棋规则进行移动,走遍棋盘上的64个方格,要求每个方格进入且只进入一次,找出一种可行的方案. 分析 说明:这个图是5*5的棋盘. 图片来 ...
- xgboost学习与总结
最近在研究xgboost,把一些xgboost的知识总结一下.这里只是把相关资源作总结,原创的东西不多. 原理 xgboost的原理首先看xgboost的作者陈天奇的ppt 英文不太好的同学可以看看这 ...
- [BZOJ4857][JSOI2016]反质数序列[最大点独立集]
题意 在长度为 \(n\) 的序列 \(a\) 中选择尽量长的子序列,使得选出子序列中任意两个数的和不为质数. \(n\leq3000\ ,a_i\leq10^5\). 分析 直接按照奇偶性建立二分图 ...
- 第二十九章 springboot + zipkin + mysql
zipkin的数据存储可以存在4个地方: 内存(仅用于测试,数据不会持久化,zipkin-server关掉,数据就没有了) 这也是之前使用的 mysql 可能是最熟悉的方式 es Cassandra ...
- 设计模式 笔记 迭代器模式 Iterator
//---------------------------15/04/26---------------------------- //Iterator 迭代器模式----对象行为型模式 /* 1:意 ...
- NetBeans的(默认)快捷键
NetBeans的(默认)快捷键 1.完成代码:ctrl+\ //任何地方按下此组合键,均会提示相应的参考字段: 2.错误提示:alt + enter //顾名思义,当系统报错时,按下此组合可以查看 ...
- Asp.net MVC Razor常见问题及解决方法(转载>云中客)
没有经验的童鞋就是这样磕磕碰碰出来的经验. 1,Datatype的错误提示消息无法自定义 这也许是Asp.net MVC的一个Bug.ViewModel中定义了DataType为Date字段: 1 2 ...