CF418D Big Problems for Organizers 树的直径、ST表
题目传送门:http://codeforces.com/problemset/problem/418/D
大意:给出一棵有$N$个节点的树,所有树边边权为$1$,给出$M$次询问,每个询问给出$x,y$两个节点,求$max_{i=1}^N\{min\{dis_{i,x},dis_{i,y}\}\}$。$N,M \leq 10^5$
倍增+长链剖分这种东西才不会写$qwq$所以写个思维难度大一点的直径写法。
我们考虑将一条直径拎出来,这样就相当于链上挂了若干棵树。因为树的直径有一个很好的性质:树上距离任意一个节点最远的点必定是两直径端点之一,所以不会存在任何一种情况,某一个询问达到的最大距离的点与给出的其中一个节点在一棵挂在直径上的子树上,所以可以将问题简化。
考虑以下几种情况:
$1.x,y$在同一直径上子树内,深度较浅的点的范围就一定会覆盖直径,答案就是直径两端点到深度较浅点的长度的较大值
$2.$我们把两个节点对应路径上的中点求出来,如果中点与$x$或$y$在同一子树内,那么另一个点的范围必须会覆盖直径,与$1$情况类似
$3.$如果在步骤$2$中求出的中点在直径上,我们就可以沿着中点劈开成两个连通块(如果中点在直径的某个点上,随意将其划入任何一个连通块),两边求出来的较大值就是答案。考虑如何求这个值。对于$x$控制的区域,在$x$子树对应的直径上的点左边的区域中,最大距离所在的点就是直径最左边的点,而对于其右边的直径上的点则与其连接子树的最大深度和到$x$所在直径点的距离有关,右边类似。这就是区间$RMQ$问题,可以使用$ST$表进行维护。时间复杂度为$O(NlogN+M)$
#include<bits/stdc++.h>
#define MAXN 100010
using namespace std;
inline int read(){
;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = (a << ) + (a << ) + (c ^ ');
c = getchar();
}
return a;
}
struct Edge{
int end , upEd;
}Ed[MAXN << ];
][] , bef[MAXN] , root[MAXN] , be[MAXN] , logg[MAXN];
int N , cntEd , maxD , maxDir , cntRoot;
bool isRoot[MAXN];
inline void addEd(int a , int b){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
}
void dfsForZJ(int k , int fa , int dep){
if(dep > maxD){
maxD = dep;
maxDir = k;
}
bef[k] = fa;
for(int i = head[k] ; i ; i = Ed[i].upEd)
if(Ed[i].end != fa)
dfsForZJ(Ed[i].end , k , dep + );
}
inline void findZJ(int start , int end){
isRoot[root[++cntRoot] = end] = ;
while(end != start)
isRoot[root[++cntRoot] = end = bef[end]] = ;
}
void dfsForDep(int k , int fa , int belong){
be[k] = belong;
for(int i = head[k] ; i ; i = Ed[i].upEd)
if(!isRoot[Ed[i].end] && Ed[i].end != fa){
maxDep[Ed[i].end] = dep[Ed[i].end] = dep[k] + ;
dfsForDep(Ed[i].end , k , belong);
maxDep[k] = max(maxDep[k] , maxDep[Ed[i].end]);
}
}
void init(){
; i <= cntRoot ; i++){
dfsForDep(root[i] , , i);
ST[i][][] = maxDep[root[i]] - i;
ST[i][][] = maxDep[root[i]] + i;
}
; << i <= cntRoot ; i++)
; j + ( << i) - <= cntRoot ; j++){
ST[j][i][] = max(ST[j][i - ][] , ST[j + ( << i - )][i - ][]);
ST[j][i][] = max(ST[j][i - ][] , ST[j + ( << i - )][i - ][]);
}
}
inline int query(int l , int r , int dir){
if(l > r)
return -0x3f3f3f3f;
];
<< t) + ][t][dir]);
}
int main(){
N = read();
; i <= ; i++)
logg[i] = logg[i >> ] + ;
; i < N ; i++){
int a = read() , b = read();
addEd(a , b);
addEd(b , a);
}
dfsForZJ( , , );
maxD = ;
int t = maxDir;
dfsForZJ(t , , );
findZJ(t , maxDir);
init();
int M = read();
;
while(M--){
int X = read() , Y = read();
if(be[X] > be[Y])
swap(X , Y);
if(be[X] == be[Y])
lastans = min(dep[X] , dep[Y]) + max(be[X] - , cntRoot - be[X]);
else{
int t = be[X] + be[Y] + dep[Y] - dep[X];//这个算中点的方法比较迷诶……
)
lastans = dep[Y] + max(be[Y] - , cntRoot - be[Y]);
else
)
lastans = dep[X] + max(be[X] - , cntRoot - be[X]);
else{
t >>= ;
lastans = max(max(be[X] - , query(be[X] + , t , ) - be[X]) + dep[X]
, max(query(t + , be[Y] - , ) + be[Y] , cntRoot - be[Y]) + dep[Y]);
}
}
cout << lastans << endl;
}
;
}
CF418D Big Problems for Organizers 树的直径、ST表的更多相关文章
- [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)
[51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...
- CF418D Big Problems for Organizers
传送门 题意,给一棵树,每次给两个点\(x,y\),求\(\max_{i=1}^{n}(\min(di_{x,i},di_{y,i}))\) 看std看了好久 以下是一个优秀的在线做法,\(O(nlo ...
- Codevs 4373 窗口(线段树 单调队列 st表)
4373 窗口 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题目描述 Description 给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只 ...
- st表、树状数组与线段树 笔记与思路整理
已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...
- poj2631 求树的直径裸题
题目链接:http://poj.org/problem?id=2631 题意:给出一棵树的两边结点以及权重,就这条路上的最长路. 思路:求实求树的直径. 这里给出树的直径的证明: 主要是利用了反证法: ...
- poj1985 Cow Marathon (求树的直径)
Cow Marathon Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 3195 Accepted: 1596 Case ...
- VIJOS1476旅游规划[树形DP 树的直径]
描述 W市的交通规划出现了重大问题,市政府下决心在全市的各大交通路口安排交通疏导员来疏导密集的车流.但由于人员不足,W市市长决定只在最需要安排人员的路口安放人员.具体说来,W市的交通网络十分简单,它包 ...
- poj2631 树的直径
设s-t是这棵树的直径,那么对于任意给予的一点,它能够到达的最远的点是s或者t. 这样我们可以通过2次bfs找到树的直径了. #include<cstdio> #include<qu ...
- 【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)
1912: [Apio2010]patrol 巡逻 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1034 Solved: 562[Submit][St ...
随机推荐
- C# 6 元组应用 Part 1:方便的字典工厂方法
首先是简单的实现: public static class CollectionExtensions { public static IDictionary<TKey, TValue> M ...
- MVC与单元测试实践之健身网站(五)-系统信息、前台入口
Fit项目停滞了一段时间,现在继续吧.上一篇完成了动作文本和配图的添加.编辑等内容.接下来要完成的是后台的最后一个模块:系统信息:以及前台的入口:关于注册.登录.修改密码等. 一 系统信息 a) 用户 ...
- Android 将数据写入Execl格式导出U盘、发送邮件
创建Execl.写入Execl数据.导入U盘 public WriteExcel(Context mContext){ this.mContext = mContext; } // 创建excel表 ...
- retrofit框架接口调用时候报Throwing new exception
最近在开发的时候遇到了一个很坑的问题,在三星6.0手机上请求接口时候报了一个异常:Throwing new exception 'length=1658; index=3248' with unexp ...
- (后台)org.apache.catalina.connector.ClientAbortException: null
比如错误日志是这样的: org.apache.catalina.connector.ClientAbortException: null 那么问题基本上就是服务器准备进行response的时候,发现连 ...
- 12、多线程:Threading、守护线程
线程与进程: 线程对于进程来说,就好似工厂里的工人,分配资源是分配到工厂,工人再去处理. 线程是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属 ...
- Python中DataFrame关联
df = pd.merge( df, # 左 wzplbm, # 右 left_on = ['WZBM','ZBWZMC'], # 左DataFrame匹配列 right_on = ['WZPLBM' ...
- [20171106]修改show spparameter的显示宽度.txt
[20171106]修改show spparameter的显示宽度.txt --//很多年前做的,修改show parameter的显示宽度.--//链接: [20121023]改变show para ...
- 使用linq语句进行联表查询
假设你有一个父表(例如:汽车),其关联一个子表,例如轮子(一对多).现在你想对于所有的父表汽车,遍历所有汽车,然后打印出来所有轮子的信息.默认的做法将是: SELECT CarId FROM Cars ...
- Linux下内存查看命令
在Linux下面,我们常用top命令来查看系统进程,top也能显示系统内存.我们常用的Linux下查看内容的专用工具是free命令. Linux下内存查看命令free详解: 在Linux下查看内存我们 ...