[51nod1766]树上的最远点对——线段树维护树的直径 大佬们的博客 Some Links

版权声明:欢迎大家转载,转载请标明出处。 https://blog.csdn.net/ylsoi/article/details/82987459

题目大意:

n个点被n-1条边连接成了一颗树,给出ab和cd两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d}
(PS 建议使用读入优化)

思路:

首先必须要知道一个结论:若集合A中的点的最远点对为(a,b),集合B中的最远点对为(c,d),那么集合AUB中的最远点对必定是a,b,c,d四个点组成的。
证明反证法即可。
于是直接用线段树维护编号连续区间的最远点对,查询直接暴力pushup。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
typedef long long ll;

using namespace std;

void File(){
	freopen("51nod1766.in","r",stdin);
	freopen("51nod1766.out","w",stdout);
}

template<typename T>void read(T &_){
	T __=0,mul=1; char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')mul=-1;
		ch=getchar();
	}
	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
	_=__*mul;
}

const int maxn=1e5+10;
int n,q;
int beg[maxn],las[maxn<<1],to[maxn<<1],w[maxn<<1],cnte=1;
int st[maxn<<1][22],dep[maxn],Log[maxn<<1],cnt,pos[maxn];

void add(int u,int v,int val){
	las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; w[cnte]=val;
	las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; w[cnte]=val;
}

void dfs(int u,int f,int d){
	st[++cnt][0]=u;
	dep[u]=d; pos[u]=cnt;
	for(int i=beg[u];i;i=las[i]){
		if(to[i]==f)continue;
		dfs(to[i],u,d+w[i]);
		st[++cnt][0]=u;
	}
}

int rmq(int l,int r){
	int k=Log[r-l+1],len=1<<k;
	return dep[st[l][k]]<dep[st[r-len+1][k]] ? st[l][k] : st[r-len+1][k];
}

int lca(int x,int y){
	x=pos[x]; y=pos[y];
	if(x>y)swap(x,y);
	return rmq(x,y);
}

int dis(int x,int y){
	int an=lca(x,y);
	return dep[x]+dep[y]-dep[an]*2;
}

struct node{
	int s,t;
	node operator + (const node & tt) const {
		node r[7]; int d[7],Max=0;
		r[1]=(node){s,t}; d[1]=dis(r[1].s,r[1].t);
		r[2]=(node){s,tt.s}; d[2]=dis(r[2].s,r[2].t);
		r[3]=(node){s,tt.t}; d[3]=dis(r[3].s,r[3].t);
		r[4]=(node){t,tt.s}; d[4]=dis(r[4].s,r[4].t);
		r[5]=(node){t,tt.t}; d[5]=dis(r[5].s,r[5].t);
		r[6]=(node){tt.s,tt.t}; d[6]=dis(r[6].s,r[6].t);
		REP(i,1,6)Max=max(Max,d[i]);
		REP(i,1,6)if(d[i]==Max)return r[i];
	}
	node operator * (const node & tt) const {
		node r[7]={0}; int d[7]={0},Max=0;
		r[2]=(node){s,tt.s}; d[2]=dis(r[2].s,r[2].t);
		r[3]=(node){s,tt.t}; d[3]=dis(r[3].s,r[3].t);
		r[4]=(node){t,tt.s}; d[4]=dis(r[4].s,r[4].t);
		r[5]=(node){t,tt.t}; d[5]=dis(r[5].s,r[5].t);
		REP(i,1,6)Max=max(Max,d[i]);
		REP(i,1,6)if(d[i]==Max)return r[i];
	}
};

struct Segment_Tree{
#define mid ((l+r)>>1)
#define lc rt<<1
#define rc rt<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
	node path[maxn<<2];
	void build(int rt,int l,int r){
		if(l==r)path[rt]=(node){l,l};
		else{
			build(lson); build(rson);
			path[rt]=path[lc]+path[rc];
		}
	}
	node query(int rt,int l,int r,int L,int R){
		if(L<=l && r<=R)return path[rt];
		if(L<=mid && R>=mid+1)return query(lson,L,R)+query(rson,L,R);
		if(L<=mid)return query(lson,L,R);
		return query(rson,L,R);
	}
}T;

void init(){
	read(n);
	int u,v,val;
	REP(i,1,n-1)read(u),read(v),read(val),add(u,v,val);
	REP(i,2,maxn*2-10)Log[i]=Log[i/2]+1;
	dfs(1,0,0);
	REP(j,1,Log[cnt]){
		int len=1<<j;
		REP(i,1,cnt-len+1)
			st[i][j]= dep[st[i][j-1]]<dep[st[i+len/2][j-1]] ? st[i][j-1] : st[i+len/2][j-1];
	}
}

void work(){
	T.build(1,1,n);
	read(q);
	int a,b,c,d;
	REP(i,1,q){
		read(a); read(b); read(c); read(d);
		node ans=T.query(1,1,n,a,b)*T.query(1,1,n,c,d);
		int di=dis(ans.s,ans.t);
		printf("%d\n",di);
	}
}

int main(){
	File();
	init();
	work();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/82987459
今日推荐