题目传送门: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表的更多相关文章

  1. [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)

    [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...

  2. CF418D Big Problems for Organizers

    传送门 题意,给一棵树,每次给两个点\(x,y\),求\(\max_{i=1}^{n}(\min(di_{x,i},di_{y,i}))\) 看std看了好久 以下是一个优秀的在线做法,\(O(nlo ...

  3. Codevs 4373 窗口(线段树 单调队列 st表)

    4373 窗口 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题目描述 Description 给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只 ...

  4. st表、树状数组与线段树 笔记与思路整理

    已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...

  5. poj2631 求树的直径裸题

    题目链接:http://poj.org/problem?id=2631 题意:给出一棵树的两边结点以及权重,就这条路上的最长路. 思路:求实求树的直径. 这里给出树的直径的证明: 主要是利用了反证法: ...

  6. poj1985 Cow Marathon (求树的直径)

    Cow Marathon Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 3195   Accepted: 1596 Case ...

  7. VIJOS1476旅游规划[树形DP 树的直径]

    描述 W市的交通规划出现了重大问题,市政府下决心在全市的各大交通路口安排交通疏导员来疏导密集的车流.但由于人员不足,W市市长决定只在最需要安排人员的路口安放人员.具体说来,W市的交通网络十分简单,它包 ...

  8. poj2631 树的直径

    设s-t是这棵树的直径,那么对于任意给予的一点,它能够到达的最远的点是s或者t. 这样我们可以通过2次bfs找到树的直径了. #include<cstdio> #include<qu ...

  9. 【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)

    1912: [Apio2010]patrol 巡逻 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1034  Solved: 562[Submit][St ...

随机推荐

  1. Python之历史

    一.python简单介绍 python的创始人:吉多·范罗苏姆(Guido van Rossum),于1989年开始编写,到1991年完成了第一个python编译器.它是用C语言实现的,并能够调用C语 ...

  2. 安卓开发_数据存储技术_sqlite

    一.SQLite SQLite第一个Alpha版本诞生于2000年5月,它是一款轻量级数据库,它的设计目标是嵌入式的,占用资源非常的低,只需要几百K的内存就够了.SQLite已经被多种软件和产品使用 ...

  3. flume组件汇总 source、sink、channel

    Flume Source Source类型 说明 Avro Source 支持Avro协议(实际上是Avro RPC),内置支持 Thrift Source 支持Thrift协议,内置支持 Exec  ...

  4. asp.net mvc5中的过滤器重写

    asp.net mvc5中增加了一种过滤器类型叫过滤器重写,这种过滤器类型可以在操作或者控制器上忽略更高层次上设置的过滤器类型,它可以重写五种基本的过滤器接口类型:IAuthenticationFil ...

  5. What To Do When MySQL Runs Out of Memory: Troubleshooting Guide

    In this article, I will show you how to use the new version of MySQL (5.7+) and how to troubleshoot ...

  6. kettle 合并记录步骤中的 关键字段和 比较字段的说明

    该步骤用于将两个不同来源的数据合并,这两个来源的数据分别为旧数据和新数据,该步骤将旧数据和新数据按照指定的关键字匹配.比较.合并. 需要设置的参数: 旧数据来源:旧数据来源的步骤 新数据来源.新数据来 ...

  7. Git永久删除文件和历史记录

    目录 Git永久删除文件和历史记录 使用filter-branch 添加到.gitignore文件里并push修改后的repo 清理和回收空间 Git永久删除文件和历史记录 造成你想从git存储库中永 ...

  8. Bash On Windows上安装JDK

    1. 引言 由于实习生转正,公司给配了一台新电脑,配置不用多说,16G内存,i7-7700的CPU,128SSD的系统盘,1T的机械硬盘,虽然只有一个破核显.对于我个人而言,最重要的是系统从Windo ...

  9. 字符串之StringBuffer 与 StringBuilder的对比

    StringBuilder 和 StringBuffer是高度类似的两个类 StringBuilder是StringBuffer的版本改写,下面从几个方面简单的对比下他们的区别 原文地址:[十四]基础 ...

  10. ES5-ES6-ES7_const声明只读常量

    const 概述const声明一个只读的常量.一旦声明,常量的值就不能改变.const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值. // const P ...