主席树 || 可持久化线段树 || BZOJ 3653: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生
题解:
我很喜欢这道题。
因为A是给定的,所以实质是求二元组的个数。我们以A(即给定的P)作为基点寻找答案,那么情况分两类。一种是B为A的父亲,另一种是A为B的父亲。
第一种情况很好处理,写法见代码,懒得讲,反正很简单的。
第二种情况的话,按Dfs序建主席树,用主席树维护下标为Dep的序列,每次用Size-1(因为不能取本身;Size[i]即为以i为根的子树节点数)去更新,
询问的时候在以A为根的子树中查找Dep[A]+1~Dep[A]+K的和即可。
不思考自然是看不懂的。
代码:
- #include<cstdio>
- #include<cstring>
- #include<iostream>
- #define ll long long
- #define max(a,b) ((a)>(b)?(a):(b))
- using namespace std;
- inline ll rd(){
- ll x=,f=;char c=getchar();
- while(c<''||c>''){if(c=='-')f=-; c=getchar();}
- while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
- return f*x;
- }
- const int maxn=(3e5)+,maxq=(3e5)+;
- int N,Q,num_edge=,edge_head[maxn],U,V,Le[maxn],Ri[maxn],P,root[maxn],num_treenode=,maxdep;
- int Dfn[maxn],num_dfn=;
- struct Edge{int to,nx;}edge[maxn<<];
- ll Dep[maxn],Size[maxn],K,w,ans;
- inline void Add_edge(int from,int to){
- edge[++num_edge].nx=edge_head[from];
- edge[num_edge].to=to;
- edge_head[from]=num_edge;
- return;
- }
- struct Tree{int l,r,ls,rs;ll sum;}t[(maxn<<)+(maxn*)];
- inline void Build(int x,int l,int r){//建以深度为下标的主席树
- t[x].l=l;t[x].r=r;int mid=(l+r)>>;
- if(l==r)return;
- Build(t[x].ls=++num_treenode,l,mid);
- Build(t[x].rs=++num_treenode,mid+,r);
- return;
- }
- inline void Dfs(int x,int fa){
- Dfn[++num_dfn]=x;
- Le[x]=num_dfn;
- Dep[x]=Dep[fa]+;
- maxdep=max(maxdep,Dep[x]);
- Size[x]=;
- for(int i=edge_head[x];i;i=edge[i].nx){
- int y=edge[i].to;
- if(y!=fa){
- Dfs(y,x);
- Size[x]+=Size[y];
- }
- }
- Ri[x]=num_dfn;
- return;
- }
- inline void Update(int u,int x,int q,int s){
- int l=t[u].l,r=t[u].r,mid=(l+r)>>;
- t[x].l=l;t[x].r=r;
- if(l==r&&l==q){t[x].sum=t[u].sum+s; return;}
- if(q<=mid){
- t[x].rs=t[u].rs;
- Update(t[u].ls,t[x].ls=++num_treenode,q,s);
- }
- else{
- t[x].ls=t[u].ls;
- Update(t[u].rs,t[x].rs=++num_treenode,q,s);
- }
- t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum;
- return;
- }
- inline void Query(int u,int x,int ql,int qr){
- int l=t[u].l,r=t[u].r,mid=(l+r)>>;
- if(ql<=l&&r<=qr){
- ans=ans+t[x].sum-t[u].sum;
- return;
- }
- if(ql<=mid)Query(t[u].ls,t[x].ls,ql,qr);
- if(qr>mid) Query(t[u].rs,t[x].rs,ql,qr);
- return;
- }
- int main(){
- N=rd();Q=rd();
- for(int i=;i<N;i++){
- U=rd();V=rd();
- Add_edge(U,V);
- Add_edge(V,U);
- }
- Dep[]=-;//由于我的写法的原因,把根节点的深度设为0
- Dfs(,);
- Build(root[]=++num_treenode,,maxdep+);
- Dfn[]=;
- for(int i=;i<=num_dfn;i++)
- Update(root[Dfn[i-]],root[Dfn[i]]=++num_treenode,Dep[Dfn[i]],Size[Dfn[i]]-);
- while(Q--){
- P=rd();K=rd();
- ans=;
- //先往父亲找
- if(Dep[P]>=K)w=K;else w=Dep[P];
- ans+=w*(Size[P]-);
- //往儿子找
- Query(root[P],root[Dfn[Ri[P]]],Dep[P]+,Dep[P]+K);
- printf("%lld\n",ans);
- }
- return ;
- }
By:AlenaNuna
主席树 || 可持久化线段树 || BZOJ 3653: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生的更多相关文章
- luogu P3899 [湖南集训]谈笑风生 线段树合并
Code: #include<bits/stdc++.h> #define maxn 300002 #define ll long long using namespace std; vo ...
- [Luogu P3899] [湖南集训]谈笑风生 (主席树)
题面 传送门:https://www.luogu.org/problemnew/show/P3899 Solution 你们搞的这道题啊,excited! 这题真的很有意思. 首先,我们可以先理解一下 ...
- 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex
题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...
- [BZOJ 4771]七彩树(可持久化线段树+树上差分)
[BZOJ 4771]七彩树(可持久化线段树+树上差分) 题面 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i] ...
- 归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665
如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k ...
- 主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )
在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 [模板]可持久化线段树 1(主席树)就突然有了不详的预感2333 果然...然后我gg了!被大佬虐了! hdu 2665 Kth ...
- BZOJ.4771.七彩树(可持久化线段树)
BZOJ 考虑没有深度限制,对整棵子树询问怎么做. 对于同种颜色中DFS序相邻的两个点\(u,v\),在\(dfn[u],dfn[v]\)处分别\(+1\),\(dfn[LCA(u,v)]\)处\(- ...
- 权值线段树&&可持久化线段树&&主席树
权值线段树 顾名思义,就是以权值为下标建立的线段树. 现在让我们来考虑考虑上面那句话的产生的三个小问题: 1. 如果说权值作为下标了,那这颗线段树里存什么呢? ----- 这颗线段树中, 记录每个值出 ...
- BZOJ 3483 SGU505 Prefixes and suffixes(字典树+可持久化线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3483 [题目大意] 给出一些串,同时给出m对前缀后缀,询问有多少串满足给出的前缀后缀模 ...
随机推荐
- 一个简单的开源PHP爬虫框架『Phpfetcher』
这篇文章首发在吹水小镇:http://blog.reetsee.com/archives/366 要在手机或者电脑看到更好的图片或代码欢迎到博文原地址.也欢迎到博文原地址批评指正. 转载请注明: 吹水 ...
- phpBB3导入版面的Python脚本
关联的数据表 在phpBB3中导入版面时, 需要处理的有两张表, 一个是 forums, 一个是 acl_groups. 如果是干净的论坛, 可以不保留安装时填入的默认分区和版面, 直接用以下语句初始 ...
- MATLAB 程序计算结果出现 复数(a+bi)问题
存在对负数开根号的情况了: >> (0.777)^0.1 ans = 0.9751 >> ( ans = 0.6037 >> (0.777)^2.1 ans = 0 ...
- JS 日期补0
js日期需要yyyy-mm-dd的时候只显示yyyy-m-d,需要前面补充0,之前都是用的判断,感觉非常low.刚刚看到一个方法padStart用了用还不错,padStart是为数值补全指定位数,对应 ...
- d3绘制饼状图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- hdoj:2048
#include <iostream> using namespace std; ]; ]; int main() { int C; a[] = ; a[] = ; b[] = ; b[] ...
- 使用Go语言+Protobuf协议完成一个多人聊天室
软件环境:Goland Github地址 一.目的 之前用纯逻辑垒完了一个可登入登出的在线多人聊天室(代码仓库地址),这次学习了Protobuf协议,于是想试着更新下聊天室的版本. 主要目的是为了掌握 ...
- 2.静态AOP实现-装饰器模式
通过装饰器模式实现在RegUser()方法本身业务前后加上一些自己的功能,如:BeforeProceed和AfterProceed,即不修改UserProcessor类又能增加新功能 定义1个用户接口 ...
- vue双向绑定的时候把遍历的数组转为了字符串,并且再转回去数组进行绑定
我的问题大家可能不太懂,我详细再解释一下,就是我通过遍历一个大的数组,多层遍历之后,最后的值还是一个小的数组,形如: aaa:[ { bbb1:[ "111","&quo ...
- Shell常见问题整理
1. 使用shell进行程序设计的原因是什么? 可以快速.简单的完成编程,非常适合于编写一些执行相对简单的任务的小工具.如果有一个简单的构想,可以通过它检查自己的想法是否可行.还可以使用shell对进 ...