nowcoder172C 保护 (倍增lca+dfs序+主席树)
https://www.nowcoder.com/acm/contest/172/C
(sbw大佬太强啦 orz)
先把每一个路径(x,y)分成(x,lca),(y,lca)两个路径,然后就能发现,对于某两个(直上直下的)路径a,b,b的下端点在a的下端点子树中,且b的上端点深度<=a的上端点深度,那么b是覆盖a的。
这样的话,我们做一个dfs序,那么能覆盖某个路径的个数就是(下端点在dfs序对应的那个区间中的、上端点深度小于要覆盖的那个路径)的路径的个数。
而且比较容易发现,我们要求的其实就是dfs序那个区间里的深度第k小的路径。
这样的话,就可以搞一个主席树,以深度为权值,每条路径下端点的dfs序为时间往里加值,每次只要询问对应区间的第k小就可以。
不过要注意的是,我找出来的那个点深度大于我在做的这个点的深度的话,是不合法的,要判掉。
#include<bits/stdc++.h>
#define pa pair<int,int>
#define ll long long
using namespace std;
const int maxn=,logn=; ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} int N,M,L,Q;
int lg[maxn],dep[maxn],fa[maxn][logn];
int egh[maxn],eg[maxn*][],ect;
int pth[maxn],pt[maxn*][],pct;
int id[maxn],dfn[maxn][],tot,lst[maxn];
int ch[maxn*logn*][],sum[maxn*logn*],root[maxn*],rct; inline void adeg(int a,int b){
eg[++ect][]=b;eg[ect][]=egh[a];egh[a]=ect;
}
inline void adpt(int a,int d){
pt[++pct][]=d;pt[pct][]=pth[a];pth[a]=pct;
} void dfs(int x){
dfn[x][]=++tot;id[tot]=x;
for(int i=;fa[x][i-]&&fa[fa[x][i-]][i-];i++){
fa[x][i]=fa[fa[x][i-]][i-];
}
for(int i=egh[x];i!=-;i=eg[i][]){
if(dfn[eg[i][]][]) continue;
dep[eg[i][]]=dep[x]+;fa[eg[i][]][]=x;
L=max(L,dep[x]+);dfs(eg[i][]);
}dfn[x][]=tot;
} inline int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y]){
x=fa[x][lg[dep[x]-dep[y]]];
}if(x==y) return x;
for(int i=lg[dep[x]-];i>=;i--){
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
}return fa[x][];
} void add(int &rn,int ro,int l,int r,int x){
rn=++rct;sum[rn]=sum[ro]+;
if(l<r){int m=l+r>>;
if(x<=m){
add(ch[rn][],ch[ro][],l,m,x);ch[rn][]=ch[ro][];
}else{
add(ch[rn][],ch[ro][],m+,r,x);ch[rn][]=ch[ro][];
}
}
}
int query(int rn,int ro,int l,int r,int k){
//printf("%d %d %d %d %d %d\n",l,r,rn,ro,sum[rn],sum[ro]);
if(k>sum[rn]-sum[ro]) return -;
if(l==r) return l;
else{
int m=l+r>>,w=sum[ch[rn][]]-sum[ch[ro][]];
if(w>=k) return query(ch[rn][],ch[ro][],l,m,k);
else return query(ch[rn][],ch[ro][],m+,r,k-w);
}
} inline int solve(int x,int k){
if(!k) return dep[x]-;
int y=query(root[lst[dfn[x][]]],root[lst[dfn[x][]-]],,L,k);
if(y==-||dep[x]<y) return ;
else return dep[x]-y;
} int main(){
//freopen("protect.in","r",stdin);
int i,j,k;
N=rd(),M=rd();memset(egh,-,sizeof(egh));
for(i=,j=,k=;i<=N+;i++){
if(i>=k) j++,k<<=;lg[i]=j;
}
for(i=;i<N;i++){
int a=rd(),b=rd();
adeg(a,b);adeg(b,a);
}dep[]=;dfs();memset(pth,-,sizeof(pth));
for(i=;i<=M;i++){
int a=rd(),b=rd();
int x=lca(a,b);
adpt(a,dep[x]);adpt(b,dep[x]);
}
for(i=,k=;i<=N;i++){
for(j=pth[id[i]];j!=-;j=pt[j][]){
++k;add(root[k],root[k-],,L,pt[j][]);
}lst[i]=k;
}
Q=rd();
for(i=;i<=Q;i++){
int a=rd(),b=rd();
printf("%d\n",solve(a,b));
}
return ;
}
nowcoder172C 保护 (倍增lca+dfs序+主席树)的更多相关文章
- 【bzoj3545/bzoj3551】[ONTAK2010]Peaks/加强版 Kruskal+树上倍增+Dfs序+主席树
bzoj3545 题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询 ...
- 【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树
题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高 ...
- 2018.09.30 bzoj3551:Peaks加强版(dfs序+主席树+倍增+kruskal重构树)
传送门 一道考察比较全面的题. 这道题又用到了熟悉的kruskal+倍增来查找询问区间的方法. 查到询问的子树之后就可以用dfs序+主席树统计答案了. 代码: #include<bits/std ...
- dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448
4448: [Scoi2015]情报传递 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 588 Solved: 308[Submit][Status ...
- 【bzoj1803】Spoj1487 Query on a tree III DFS序+主席树
题目描述 You are given a node-labeled rooted tree with n nodes. Define the query (x, k): Find the node w ...
- [xdoj1216]子树第k小(dfs序+主席树)
解题关键:dfs序将树映射到区间,然后主席树求区间第k小,为模板题. #pragma comment(linker, "/STACK:1024000000,1024000000") ...
- BZOJ 3439: Kpm的MC密码 (trie+dfs序主席树)
题意 略 分析 把串倒过来插进trietrietrie上, 那么一个串的kpmkpmkpm串就是这个串在trietrietrie上对应的结点的子树下面的所有字符串. 那么像 BZOJ 3551/354 ...
- BZOJ 3551: [ONTAK2010]Peaks加强版 Kruskal重构树+dfs序+主席树+倍增
建出来 $Kruskal$ 重构树. 将询问点向上跳到深度最小,且合法的节点上. 那么,得益于重构树优美的性质,这个最终跳到的点为根的所有子节点都可以与询问点互达. 对于子树中求点权第 $k$ 大的问 ...
- 【BZOJ3772】精神污染 DFS序+主席树
[BZOJ3772]精神污染 Description 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是 ...
随机推荐
- Python从菜鸟到高手(5):数字
1 基础知识 Python语言与其他编程语言一样,也支持四则运算(加.减.乘.除),以及圆括号运算符.在Python语言中,数字分为整数和浮点数.整数就是无小数部分的数,浮点数就是有小数部分的数. ...
- C#_XML与Object转换
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.X ...
- NB-IOT_BC95_B5常用AT指令集
.AT+<cmd>=? 测试命令,用于向模块询问支持的设置项目. .AT+<cmd>? 读取命令,用于让模块上报某个命令代表的设置项当前的值. .AT+<cmd>= ...
- 求去掉一条边使最小割变小 HAOI2017 新型城市化
先求最小割,然后对残量网络跑Tarjan.对于所有满流的边,若其两端点不在同一个SCC中,则这条边是满足条件的. 证明见 来源:HAOI2017 新型城市化
- B. Interesting drink
链接 [http://codeforces.com/group/1EzrFFyOc0/contest/706/problem/B] 题意 给你n个数,q次查询,每次输入一个m,问n个数中有多少个数小于 ...
- D. Bicolorings
传送门 [http://codeforces.com/contest/1051/problem/D] 题意 相当于有个2列n行得棋盘,棋盘上的格子只能是黑或者白,问你联通块为k得方案数有多少,结果对 ...
- 20135316王剑桥Linux内核学习记笔记第七周
20135316王剑桥<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC 1000029000 一.可执行程序是怎么得来的? 编译 ...
- Linux查询用户和组的命令
root@PC-RENGUOQIANG:~# cat /etc/passwd root:x:::root:/root:/bin/bash daemon:x:::daemon:/usr/sbin:/us ...
- Docker(十三)-Docker save and load镜像保存
持久化docker的镜像或容器的方法 Docker的镜像和容器可以有两种方式来导出 docker save #ID or #Name docker export #ID or #Name docker ...
- [工作相关] 一个虚拟机上面的SAP4HANA的简单使用维护
1.公司组织竞品分析, 选择了SAP的 SAP4HANA作为竞品 这边协助同事搭建了SAP4HANA的测试环境: 备注 这个环境 应该是同事通过一些渠道获取到的. 里面是基于这个虚拟机进行的说明:: ...