51nod 1766
题意:给定一个树(10^5),m个询问(10^5),每次给定a,b,c,d,在区间[a,b]中选一个点,[c,d]选一个点,使得这两个点距离最大,输出最大距离。
题解:首先,我们有一个结论:对于一个集合的直径,如果我们将这个集合分解成两个非空集合,它的端点一定在两个非空集合的两个端这4个端点中。这非常的显然。。。
那么我们就可以做到合并两个集合,我们就可以用线段树维护每个区间的直径,就好啦,完全不用复杂的数据结构。
这道题卡时间,所以LCA要用欧拉序RMQ做。
复杂度O(nlogn)
#include<bits/stdc++.h>
using namespace std;
#define N 200005
inline int read(){
int x=,f=; char a=getchar();
while(a<'' || a>'') {if(a=='-') f=-; a=getchar();}
while(a>='' && a<='') x=x*+a-'',a=getchar();
return x*f;
}
int n,m,cnt=,euler[*N],dep[N],head[N],fi[N],dis[N],st[N][],mn[N][],Log[*N];
struct edges{
int to,c,next;
}e[N];
struct node{
int x1,x2,l,r;
}seg[*N];
struct data{
int x1,x2;
};
inline int getdis(int u,int v){
if(!u || !v) return ;
u=fi[u]; v=fi[v];
if(u>v) swap(u,v);
int p,len=Log[v-u+];
p=mn[u][len]<mn[v-(<<len)+][len]?st[u][len]:st[v-(<<len)+][len];
return dis[euler[u]]+dis[euler[v]]-*dis[p];
}
inline void update(int x){
int mx=,x1=seg[x<<].x1,x2=seg[x<<].x2,x3=seg[x<<|].x1,x4=seg[x<<|].x2,f;
if((f=getdis(x1,x2))>mx) seg[x].x1=x1,seg[x].x2=x2,mx=f; if((f=getdis(x1,x3))>mx) seg[x].x1=x1,seg[x].x2=x3,mx=f;
if((f=getdis(x1,x4))>mx) seg[x].x1=x1,seg[x].x2=x4,mx=f; if((f=getdis(x2,x3))>mx) seg[x].x1=x2,seg[x].x2=x3,mx=f;
if((f=getdis(x2,x4))>mx) seg[x].x1=x2,seg[x].x2=x4,mx=f; if((f=getdis(x3,x4))>mx) seg[x].x1=x3,seg[x].x2=x4,mx=f;
}
inline void insert(){
int u=read(),v=read(),c=read();
e[++cnt]=(edges){v,c,head[u]};head[u]=cnt;
}
void dfs(int x,int fa){
dep[x]=dep[fa]+; fi[x]=euler[]+;
for(int i=head[x];i;i=e[i].next){
if(fa==e[i].to) continue;
euler[++euler[]]=x;
dis[e[i].to]=dis[x]+e[i].c; dfs(e[i].to,x);
}
euler[++euler[]]=x;
}
inline void rmq_pre(){
for(int i=;i<=euler[];i++) st[i][]=euler[i],mn[i][]=dep[euler[i]];
for(int i=;i<=;i++)
for(int j=;j<=euler[];j++){
if(j+(<<i)->euler[]) break;
if(mn[j][i-]<mn[j+(<<(i-))][i-]) st[j][i]=st[j][i-],mn[j][i]=mn[j][i-];
else st[j][i]=st[j+(<<(i-))][i-],mn[j][i]=mn[j+(<<(i-))][i-];
}
Log[]=-; for(int i=;i<=euler[];i++) Log[i]=Log[i>>]+;
}
void build(int l,int r,int x){
seg[x].l=l; seg[x].r=r;
if(l==r) {seg[x].x1=l; seg[x].x2=; return;}
int mid=(l+r)>>;
build(l,mid,x<<);
build(mid+,r,x<<|);
update(x);
}
data merge(data tmp1,data tmp2){
int f,mx=,x1=tmp1.x1,x2=tmp1.x2,x3=tmp2.x1,x4=tmp2.x2;
data ret;
if((f=getdis(x1,x2))>mx) ret.x1=x1,ret.x2=x2,mx=f; if((f=getdis(x1,x3))>mx) ret.x1=x1,ret.x2=x3,mx=f;
if((f=getdis(x1,x4))>mx) ret.x1=x1,ret.x2=x4,mx=f; if((f=getdis(x2,x3))>mx) ret.x1=x2,ret.x2=x3,mx=f;
if((f=getdis(x2,x4))>mx) ret.x1=x2,ret.x2=x4,mx=f; if((f=getdis(x3,x4))>mx) ret.x1=x3,ret.x2=x4,mx=f;
return ret;
}
data query(int L,int R,int x){
int l=seg[x].l,r=seg[x].r;
if(l==L && r==R) {return (data){seg[x].x1,seg[x].x2};}
int mid=(l+r)>>;
if(R<=mid) return query(L,R,x<<);
else if(mid<L) return query(L,R,x<<|);
else return merge(query(L,mid,x<<),query(mid+,R,x<<|));
}
int main(){
n=read();
for(int i=;i<n;i++) insert();
dfs(,); rmq_pre(); build(,n,);
m=read();
while(m--){
int t1,t2,a=read(),b=read(),c=read(),d=read();
data tmp1=query(a,b,),tmp2=query(c,d,);
t1=max(getdis(tmp1.x1,tmp2.x1),getdis(tmp1.x1,tmp2.x2));
t2=max(getdis(tmp1.x2,tmp2.x1),getdis(tmp1.x2,tmp2.x2));
printf("%d\n",max(t1,t2));
}
return ;
}
51nod 1766的更多相关文章
- 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径
51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...
- [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)
[51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...
- 51Nod 1766 树上的最远点对
Description 一棵树,询问两个端点编号分别在在 \([a,b]\) 和 \([c,d]\) 两个区间中的最长链. Sol 线段树+ST表. 树上最长链可以合并,只需要合并两个区间最长链的两个 ...
- 51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)
题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq ...
- 51nod 1766 树上的最远点对(线段树)
像树的直径一样,两个集合的最长路也是由两个集合内部的最长路的两个端点组成的,于是我们知道了两个集合的最长路,枚举一下两两端点算出答案就可以合并了,所以就可以用线段树维护一个区间里的最长路了. #inc ...
- 51nod 1766 树上的最远点对——线段树
n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j& ...
- 【树形结构】51nod 1766 树上的最远点对
题目内容 \(n\)个点被\(n−1\)条边连接成了一颗树,边有权值\(w_i\).有\(q\)个询问,给出\([a,b]\)和\([c,d]\)两个区间,表示点的标号请你求出两个区间内各选一点之间的 ...
- 倍增/线段树维护树的直径 hdu5993/2016icpc青岛L
题意: 给一棵树,每次询问删掉两条边,问剩下的三棵树的最大直径 点10W,询问10W,询问相互独立 Solution: 考虑线段树/倍增维护树的直径 考虑一个点集的区间 [l, r] 而我们知道了有 ...
- 【51nod】1766 树上的最远点对
[题意]给定n个点的树,m次求[a,b]和[c,d]中各选出一个点的最大距离.abcd是标号区间,n,m<=10^5 [算法]LCA+树的直径理论+线段树 [题解] 树的直径性质:距离树上任意点 ...
随机推荐
- AngularJS中Route例子
代码:https://files.cnblogs.com/files/xiandedanteng/angularJSRouteSample.rar 点击‘首页’后: 点击‘电脑’后: <!DOC ...
- 【Redmine】Redmine 3.0.1 安装与配置
Redmine安装 VM安装Linux 安装Bitnami Redmine 配置环境 1.VM安装Linux 使用虚拟机安装Linux 本文使用的是Centos(CentOS-6.3-x86_64-b ...
- 服务器,数据库连接注意mysql的user表
update user set host='localhost' where user='root';
- angular 视频教程
在网上找了一些,视频教程.存在备用 angular 视频教程 百度云盘地址 小时前 1小时前 30 6 angular 4.0视频教程 链接:https://pan.baidu.com/s/1qXIt ...
- hint指定index的深入理解
http://czmmiao.iteye.com/blog/1480247创建一个表,含有位图index和b-tree index SQL> create table t as select o ...
- 关于PM的认识
1 我眼中的PM 1.1 人云“一个管理,半个专家”,我说“一个管理,两个专家” 如今,我发现我们不得不面对这样一个现实——角色兼职.我习惯上把项目分为三类:性命攸关的项目(涉及到人身安全的项目,如铁 ...
- java.lang.UnsupportedClassVersionError: Unsupported major.minor version 49.0的错误 [转]
一:要解决的问题 我们在尝鲜 JDK1.5 的时候,相信不少人遇到过 Unsupported major.minor version 49.0 错误,当时定会茫然不知所措.因为刚开始那会儿,网上与此相 ...
- linux安装svn客户端subversion及使用方法
1.下载 [maintain@HM16-213 software]$ wget http://subversion.tigris.org/downloads/subversion-deps-1.6.1 ...
- Android Camera API2中采用CameraMetadata用于从APP到HAL的参数交互
前沿: 在全新的Camera API2架构下,常常会有人疑问再也看不到熟悉的SetParameter/Paramters等相关的身影,取而代之的是一种全新的CameraMetadata结构的出现,他不 ...
- 10-客户端防表单重复提交和服务器端session防表单重复提交
/****************************************************DoFormServlet********************************** ...