BZOJ 3653: 谈笑风生(主席树)
解题思路
首先对于一个$a$来说,要求$b$和$c$,那么$a,b,c$一定在一条链上。把$b$分类讨论,如果$b$是$a$的祖宗,这个方案数就很好统计了,就是$c$在$a$的子树里随便选,产生的贡献为$(siz_a-1)*(min(k,dep_a))$。如果$b$是$a$的儿子,那么就考虑$b$作为每个点产生的贡献,发现为$siz_x-1$,那么其实要求的就是$[dfn_a+1,dfn_a+siz_a-1]\(中深度为\)[dep_a,dep_a+k]$的点的$siz$之和。发现有两个限制,可以主席树维护。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=300005;
const int M=N*21;
typedef long long LL;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
int n,q,head[N],cnt,to[N<<1],nxt[N<<1],siz[N],dfn[N],dep[N],num,bl[N];
LL ans;
struct Persistence_Segment_Tree{
LL sum[M];int ls[M],rs[M],rt[N],tot;
void build(int &x,int l,int r){
x=++tot; if(l==r) return; int mid=(l+r)>>1;
build(ls[x],l,mid); build(rs[x],mid+1,r);
}
void update(int pre,int &x,int l,int r,int pos,int k){
x=++tot; sum[x]=sum[pre]+k; if(l==r) return;
ls[x]=ls[pre]; rs[x]=rs[pre]; int mid=(l+r)>>1;
if(pos<=mid) update(ls[pre],ls[x],l,mid,pos,k);
else update(rs[pre],rs[x],mid+1,r,pos,k);
}
inline void BUILD(){
build(rt[0],1,n);
for(int i=1;i<=n;i++)
update(rt[i-1],rt[i],1,n,dep[bl[i]],siz[bl[i]]-1);
}
LL query(int u,int v,int l,int r,int L,int R){
if(L<=l && r<=R) return sum[v]-sum[u];
int mid=(l+r)>>1; LL ret=0;
if(L<=mid) ret+=query(ls[u],ls[v],l,mid,L,R);
if(mid<R) ret+=query(rs[u],rs[v],mid+1,r,L,R);
return ret;
}
}tree;
inline void add(int bg,int ed){
to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}
void dfs(int x,int F,int d){
dep[x]=d; siz[x]=1; dfn[x]=++num; bl[num]=x;
for(int i=head[x];i;i=nxt[i]){
int u=to[i]; if(u==F) continue;
dfs(u,x,d+1); siz[x]+=siz[u];
}
}
int main(){
n=rd(),q=rd(); int x,y;
for(int i=1;i<n;i++){
x=rd(),y=rd();
add(x,y),add(y,x);
}
dfs(1,0,1); tree.BUILD();
while(q--){
x=rd(),y=rd(); ans=(LL)min(dep[x]-1,y)*(siz[x]-1);
ans+=tree.query(tree.rt[dfn[x]],tree.rt[dfn[x]+siz[x]-1],1,n,dep[x],min(n,dep[x]+y));
printf("%lld\n",ans);
}
return 0;
}
BZOJ 3653: 谈笑风生(主席树)的更多相关文章
- 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: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生
题面:P3899 [湖南集训]谈笑风生 题解: 我很喜欢这道题. 因为A是给定的,所以实质是求二元组的个数.我们以A(即给定的P)作为基点寻找答案,那么情况分两类.一种是B为A的父亲,另一种是A为B的 ...
- bzoj 3653: 谈笑风生【dfs序+主席树】
考虑b的两种情况,一种是p的祖先,这种点有min(k,de[p]-1)个,然后每个这种b都有si[p]-1个c点可选: 另一种是p的子孙,要求是在p的子树内且deep在de[p]+1~de[p]+k之 ...
- BZOJ.3653.谈笑风生(长链剖分/线段树合并/树状数组)
BZOJ 洛谷 \(Description\) 给定一棵树,每次询问给定\(p,k\),求满足\(p,a\)都是\(b\)的祖先,且\(p,a\)距离不超过\(k\)的三元组\(p,a,b\)个数. ...
- BZOJ 3653: 谈笑风生(离线, 长链剖分, 后缀和)
题意 给你一颗有 \(n\) 个点并且以 \(1\) 为根的树.共有 \(q\) 次询问,每次询问两个参数 \(p, k\) .询问有多少对点 \((p, a, b)\) 满足 \(p,a,b\) 为 ...
- BZOJ 3524 Couriers | 主席树
BZOJ 3524 Couriers 题意 求一个区间内出现超过区间长度的一半的数,如果没有则输出0. 题解 我可能太菜了吧--这道题愣是没想出来-- 维护权值主席树,记录每个数都出现过多少次: 查询 ...
- BZOJ 3653 谈笑风生
ORZ blutrex...... 主席树. #include<iostream> #include<cstdio> #include<cstring> #incl ...
- bzoj 2588 树上主席树
主席树上树,对于每个节点,继承其父亲的,最后跑f[x]+f[y]-f[lca]-f[fa[lca]] 去重竟然要减一,我竟然不知道?? #include<cstdio> #include& ...
随机推荐
- 【LeetCode 96】不同的二叉搜索树
题目链接 [题解] 我们可以枚举这棵树的根节点在i处. 现在问题就变成. 1..i-1这i-1个节点组成的树和i+1..n这n-i个节点组成的树的个数的问题了. 假设他们俩的结果分别是cnt1和cnt ...
- python中模块介绍
一,模块概念 在计算机程序开发的过程当中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护.为了编码更加容易维护,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码 ...
- 20175126《Java程序设计》第十周学习总结
# 20175126 2016-2017-2 <Java程序设计>第十周学习总结 ## 教材学习内容总结 - 本周学习方式主要为手动敲代码并理解内容学习. -本周学习十二章,主要内容如下: ...
- idea中以maven工程的方式运行tomcat源码
0. 准备环境 idea+jdk8+tomcat源码 1.下载tomcat源码: http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/ ...
- 第一次刷Leetcode,为什么耗费很多时间
Leetcode第2题思考过程分析:耗费的时间与思考过程 1. 审题耗费了很长时间,英文看不懂.两个单链表代表了两个整数,整数逆序,(2 -> 4 -> 3) + (5 -> 6 - ...
- The life-saving straw
English learning In contemporary world, English learning has gained great popularity and it is of ...
- LeetCode:旋转数组
最近看了一道题,自己做个过后又参考了网上的解法,为了加深对这个解法的理解和记忆于是有了这篇博客,供自己以后复习用 题目: 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 ...
- urllib库爬取实例
from urllib import request import random def spider(url): user_agent_list = [ "Mozilla/5.0 (Win ...
- for,while,do while语句区别以及常见死循环格式
1.三种循环语句的区别: do...while循环至少执行一次循环体. 而for,while循环必须先判断条件是否成立,然后决定是否执行循环体语句. for循环和while循环的区别: 如果你想在循环 ...
- Python爬虫抓取 python tutorial中文版,保存为word
看到了中文版的python tutorial,发现是网页版的,刚好最近在学习爬虫,想着不如抓取到本地 首先是网页的内容 查看网页源码后发现可以使用BeautifulSoup来获取文档的标题和内容,并保 ...