传送门

题意,给一棵树,每次给两个点\(x,y\),求\(\max_{i=1}^{n}(\min(di_{x,i},di_{y,i}))\)

看std看了好久

以下是一个优秀的在线做法,\(O(nlogn)\)预处理,每次询问可以做到\(O(1)\)

首先把直径扣出来,然后就可以把整棵树看成一条直径上挂了n棵树,预处理每个点到直径的最短距离,和直径上每个点挂的树中距离这个点最远的距离\(d_i\)

对于每次询问,造成答案的点要么是直径的端点,要么是两个点路径上的某个直径点挂的树的最远距离的点,于是可以分类讨论.第一类比较好算,第二类的话,用个st表存\(d_i\),每次在距离\(x\)和\(y\)更近的区间内取最大值,再加加减减

详见代码

#include<bits/stdc++.h>
#define il inline
#define re register
#define LL long long
#define ull unsigned long long
#define db double
#define eps (1e-7) using namespace std;
const int N=100000+10;
il LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
il void add(int x,int y)
{
++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int n,nn,m,st[N],de[N],fa[N],a1,a2,rtt,id[N],d[N],lz[N];
int ma[N][18],mi[N][18];
bool v[N];
void dfs(int x,int ffa)
{
if(de[x]>de[rtt]) rtt=x;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa) continue;
de[y]=de[x]+1,fa[y]=x;
dfs(y,x);
}
}
void dd(int x,int ffa,int ii)
{
id[x]=ii,de[x]=de[ffa]+1; //把深度处理成到直径上点的距离
d[ii]=max(d[ii],de[x]);
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa||v[y]) continue;
dd(y,x,ii);
}
}
il void init()
{
for(int i=1;i<=m;i++) dd(st[i],0,i),lz[i]=log2(i);
for(int i=1;i<=m;i++) ma[i][0]=d[i]+i,mi[i][0]=d[i]-i;
for(int j=1;j<=nn;j++)
for(int i=1;i+(1<<(j-1))<=m;i++)
{
ma[i][j]=max(ma[i][j-1],ma[i+(1<<(j-1))][j-1]);
mi[i][j]=max(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
}
}
il int quer(int l,int r,int o)
{
if(l>r) return -1e9;
int j=lz[r-l+1];
if(o==1) return max(mi[l][j],mi[r-(1<<j)+1][j]);
return max(ma[l][j],ma[r-(1<<j)+1][j]);
} int main()
{
n=rd();
nn=log(n)/log(2)+1;
for(int i=1;i<n;i++)
{
int x=rd(),y=rd();
add(x,y);
}
dfs(1,0),a1=rtt,rtt=0,fa[a1]=0,dfs(a1,0),a2=rtt;
int nw=a2;
while(nw)
{
st[++m]=nw,v[nw]=true,nw=fa[nw];
}
for(int i=1;i<=m/2;i++) swap(st[i],st[m-i+1]);
de[0]=-1,init();
int q=rd(),an=0;
while(q--)
{
int x=rd(),y=rd();
an=0;
if(id[x]>id[y]) swap(x,y);
LL ss=id[x]-de[x]+id[y]+de[y]; //ss其实是x和y路径上中间点的直径点编号*2
if(id[x]==id[y]) an=max(id[x]-1,m-id[y])+min(de[x],de[y]);
else if(ss<=id[x]*2) an=max(id[y]-1,m-id[y])+de[y];
else if(ss>=id[y]*2) an=max(id[x]-1,m-id[x])+de[x];
else ss/=2,an=max(max(id[x]-1,quer(id[x]+1,ss,0)-id[x])+de[x],de[y]+max(m-id[y],quer(ss+1,id[y]-1,1)+id[y])); //对于x,到中间点区间内的答案为max(id[i]-id[x]+d[i]),y类似
printf("%d\n",an);
}
return 0;
}

CF418D Big Problems for Organizers的更多相关文章

  1. CF418D Big Problems for Organizers 树的直径、ST表

    题目传送门:http://codeforces.com/problemset/problem/418/D 大意:给出一棵有$N$个节点的树,所有树边边权为$1$,给出$M$次询问,每个询问给出$x,y ...

  2. [JZOJ3690] 【CF418D】Big Problems for Organizers

    题目 题目大意 给你一棵树,然后有一堆询问,每次给出两个点. 问所有点到两个点中最近点的距离的最大值. 正解 本来打了倍增,然后爆了,也懒得调-- 显然可以在两个点之间的路径的中点处割开,一边归一个点 ...

  3. Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]

    题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_di ...

  4. Big Problems for Organizers CodeForces - 418D (贪心,直径)

    大意: 给定n结点树, m个询问, 每次给出两个旅馆的位置, 求树上所有结点到最近旅馆距离的最大值 先考虑一些简单情形. 若旅馆只有一个的话, 显然到旅馆最远的点是直径端点之一 若树为链的话, 显然是 ...

  5. @codeforces - 418D@ Big Problems for Organizers

    目录 @description@ @solution@ @accepted code@ @details@ @description@ n 个点连成一棵树,经过每条边需要花费 1 个单位时间. 现给出 ...

  6. Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译

    本文是Unity官方教程,性能优化系列的第二篇<Diagnosing performance problems using the Profiler window>的简单翻译. 相关文章: ...

  7. MS SQL错误:SQL Server failed with error code 0xc0000000 to spawn a thread to process a new login or connection. Check the SQL Server error log and the Windows event logs for information about possible related problems

          早晨宁波那边的IT人员打电话告知数据库无法访问了.其实我在早晨也发现Ignite监控下的宁波的数据库服务器出现了异常,但是当时正在检查查看其它服务器发过来的各类邮件,还没等到我去确认具体情 ...

  8. Problems about trees

    Problems (1) 给一棵带边权的树,求遍历这棵树(每个节点至少经过一次)再回到起点的最短路程. 答案是显然的:边权之和的两倍. (2)给一棵带边权的树,求遍历这棵树(每个节点至少经过一次)的最 ...

  9. Problems with MMM for mysql(译文)

    Problems with mmm for mysql posted in MySQL by shlomi 原文:http://code.openark.org/blog/mysql/problems ...

随机推荐

  1. java解析Json字符串之懒人大法

    面对Java解析Json字符串的需求,有很多开源工具供我们选择,如google的Gson.阿里巴巴的fastJson.在网上能找到大量的文章讲解这些工具的使用方法.我也是参考这些文章封装了自己的Jso ...

  2. zookeeper 四字命令

    zookeeper四字命令   ZooKeeper3.4.6支持某些特定的四字命令字母与其的交互.它们大多是查询命令,用来获取 ZooKeeper 服务的当前状态及相关信息.用户在客户端可以通过 te ...

  3. 通俗理解TCP/IP协议三次握手四次分手流程

    转自:https://blog.csdn.net/special23/article/details/54137298 三次握手流程 客户端发个请求“开门呐,我要进来”给服务器 服务器发个“进来吧,我 ...

  4. [luogu3455][POI2007]ZAP-Queries【莫比乌斯反演】

    题目描述 FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d.作为FGD的同学,FGD希望得 ...

  5. Linux中使用Electronic WeChat客户端

    微信推出了Windows版和Mac版,一直没有推出也不会推出Linux版本,这就催生了Electronic WeChat(https://github.com/geeeeeeeeek/electron ...

  6. 洛谷P1247 取火柴游戏

    经典NIM游戏. 取XOR和即可. 注意输出方案时,找到大于异或和sum的,变为a[i] ^ sum即可. #include <cstdio> ; int a[N]; int main() ...

  7. 【LOJ#6283】数列分块7

    题目大意:维护一个 N 个数组成的序列,支持区间加.区间乘.单点询问. 题解:在每一个块中维护两个标记,即:整块加和的标记和整块乘积的标记.不过由于有两个标记,涉及到计算区间总和的顺序问题. 一个指定 ...

  8. win32: 查询滚动条相关信息的注意事项

    今天打算判断一个窗口是否出现垂直滚动条,我的代码: SCROLLINFO si; //滚动条信息结构体                    si.cbSize = sizeof(SCROLLINFO ...

  9. 部署高可用keepalived组件

    本文档讲解使用 keepalived 和 haproxy 实现 kube-apiserver 高可用的步骤: keepalived 提供 kube-apiserver 对外服务的 VIP: hapro ...

  10. 浅谈python函数签名

    函数签名对象,表示调用函数的方式,即定义了函数的输入和输出. 在Python中,可以使用标准库inspect的一些方法或类,来操作或创建函数签名. 获取函数签名及参数 使用标准库的signature方 ...