ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

#直径,线段树#51nod 1766 树上的最远点对

2021-11-18 07:31:34  阅读:182  来源: 互联网

标签:return 51nod 线段 dis int rec now 1766 Dis


题目

多组询问,在 \([a,b]\) 和 \([c,d]\) 中分别选一个点 \(x,y\) ,使得 \(dis(x,y)\) 最大


分析

考虑直径的一个性质,两个点集两条直径的四个端点可能成为合并后点集的直径,

用线段树维护区间直径询问时合并即可,LCA可以用dfs序 \(O(1)\) 询问


代码

#include <cstdio>
#include <cctype>
using namespace std;
const int N=100011; struct node{int y,w,next;}e[N<<1];
struct rec{int x,y;}w[N<<2];
int dep[N],dis[N],f[N<<1][18],two[18],lg[N<<1],dfn[N],as[N],n,tot,et=1;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
int max(int a,int b){return a>b?a:b;}
void dfs(int x,int fa){
	dep[x]=dep[fa]+1,f[dfn[x]=++tot][0]=x;
	for (int i=as[x];i;i=e[i].next)
	if (e[i].y!=fa){
		dis[e[i].y]=dis[x]+e[i].w;
		dfs(e[i].y,x),f[++tot][0]=x;
	}
}
int Get_Min(int x,int y){return dep[x]<dep[y]?x:y;}
int lca(int x,int y){
	int l=dfn[x],r=dfn[y];
	if (l>r) l^=r,r^=l,l^=r;
	int z=lg[r-l+1];
	return Get_Min(f[l][z],f[r-two[z]+1][z]);
}
int Dis(int x,int y){return dis[x]+dis[y]-2*dis[lca(x,y)];}
rec pup(rec A,rec B){
	rec t=A; int d=Dis(A.x,A.y),now;
	now=Dis(B.x,B.y); if (now>d) d=now,t=B;
	now=Dis(A.x,B.x); if (now>d) d=now,t=(rec){A.x,B.x};
	now=Dis(A.x,B.y); if (now>d) d=now,t=(rec){A.x,B.y};
	now=Dis(A.y,B.x); if (now>d) d=now,t=(rec){A.y,B.x};
	now=Dis(A.y,B.y); if (now>d) d=now,t=(rec){A.y,B.y};
	return t;
}
void build(int k,int l,int r){
	if (l==r){
		w[k]=(rec){l,l};
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	w[k]=pup(w[k<<1],w[k<<1|1]);
}
rec query(int k,int l,int r,int x,int y){
	if (l==x&&r==y) return w[k];
	int mid=(l+r)>>1;
	if (y<=mid) return query(k<<1,l,mid,x,y);
	else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
	    else return pup(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
int main(){
	n=iut(),lg[0]=-1,two[0]=1;
	for (int i=1;i<18;++i) two[i]=two[i-1]<<1;
	for (int i=1;i<n;++i){
		int x=iut(),y=iut(),w=iut();
		e[++et]=(node){y,w,as[x]},as[x]=et;
		e[++et]=(node){x,w,as[y]},as[y]=et;
	}
	dfs(1,0);
	for (int i=1;i<=tot;++i) lg[i]=lg[i>>1]+1;
	for (int j=1;j<=lg[tot];++j)
	for (int i=1;i+two[j]-1<=tot;++i)
	    f[i][j]=Get_Min(f[i][j-1],f[i+two[j-1]][j-1]);
	build(1,1,n);
	for (int Q=iut();Q;--Q,putchar(10)){
		int lx=iut(),ly=iut(),rx=iut(),ry=iut(); rec tl=query(1,1,n,lx,ly),tr=query(1,1,n,rx,ry);
		print(max(max(Dis(tl.x,tr.x),Dis(tl.x,tr.y)),max(Dis(tl.y,tr.x),Dis(tl.y,tr.y))));
	}
	return 0;
} 

标签:return,51nod,线段,dis,int,rec,now,1766,Dis
来源: https://www.cnblogs.com/Spare-No-Effort/p/15570428.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有