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

题目

多组询问,在 \([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;
} 
上一篇:【51nod】2092 翻转数组


下一篇:51Nod 1432 独木舟