3700: 发展城市

这篇博客介绍了一种使用RMQ(Range Minimum Query)解决寻找两个路径交点的方法。通过求解路径[a, b]和[c, d]的最近公共祖先,并判断它们是否在另一路径上,来确定交点。博主还提到了处理浮点数精度问题和数据结构优化的技巧。" 125483469,5749843,Angular项目中的Mock.js应用,"['Angular', '前端框架', '开发工具', '接口测试', '数据模拟']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题需要大量的lca,预处理是可以,但是会写死,因此采用rmq。
先学会如何求两个路径[a,b],[c,d]的交。
只要分别求c,d到[a,b]距离最近的点[u,v],然后判u,v是否在[c,d]上即可。下面以用c求u为例。
r<-lca(a,b)
if lca(r,c)!=r then u<-r
else if lca(a,c)!=r then u<-lca(a,c)
else u<-lca(b,c)
然后检验。
r<-lca(c,d)
u∈[c,d]当且仅当u在r的子树中(lca(u,r)==r)且lca(c,u)与lca(d,u)中有一个为u
同理求出并检验v
然后分类讨论。设s1、t1为[a,b]上的那个人到达、离开[u,v]的时间,s2、t2同理。
然后由于这些数是浮点数(被v除过了),精度抖来抖去很麻烦,就把分母都乘到对面去,但要记得开long long !
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<bitset>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pii pair<int,int>
#define mkp make_pair
#define X first
#define Y second
#define N 100005
#define NN 1005
#define inf 10000000
LL n,m,A[NN],B[NN],V[NN],ans;
LL he[N],ne[N<<1],W[N<<1],to[N<<1],tot;
LL lg[N<<1],dep[N],deep[N],phi[N<<1],id,pos[N],Min[N<<1][20];
LL read(){
	LL x=0;char ch=G;bool flg=0;
	while((ch<48||ch>57)&&ch!=45)ch=G;
	if(ch==45)flg=1,ch=G;
	for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
	return flg?-x:x;
}
void add(LL x,LL y,LL z){
	to[++tot]=y;W[tot]=z;ne[tot]=he[x];he[x]=tot;
}
void DFS(LL x,LL e){
	LL y,i;dep[phi[pos[x]=++id]=x]=dep[to[e]]+1;
	for(i=he[x];i;i=ne[i])if(i!=e){
		deep[y=to[i]]=deep[x]+W[i];DFS(y,i^1);phi[++id]=x;
	}
}
LL les(LL x,LL y){
	return dep[x]<dep[y]?x:y;
}
LL rmq(LL x,LL y){
	x=pos[x];y=pos[y];if(x>y)swap(x,y);
	LL tmp=lg[y-x+1];
	return les(Min[x][tmp],Min[y-(1<<tmp)+1][tmp]);
}
LL getd(LL x,LL y){
	return deep[x]+deep[y]-(deep[rmq(x,y)]<<1);
}
bool check(LL x,LL y){
	LL z1=rmq(A[x],B[x]),z2=rmq(A[y],B[y]),z3,z4,z5,a,b;
	if((z3=rmq(A[y],z1))!=z1)a=z1;
	else if((z4=rmq(A[y],A[x]))!=z1)a=z4;
	else a=rmq(A[y],B[x]);
	if(rmq(a,A[y])!=a&&rmq(a,B[y])!=a||rmq(a,z2)!=z2)return 0;
	if((z3=rmq(B[y],z1)!=z1))b=z1;
	else if((z4=rmq(B[y],A[x]))!=z1)b=z4;
	else b=rmq(B[y],B[x]);
	if(rmq(b,A[y])!=b&&rmq(b,B[y])!=b||rmq(b,z2)!=z2)return 0;
	LL d=getd(a,b),d1=getd(A[x],a),d2=getd(A[y],a);
	bool flg=0;if(d1>getd(A[x],b))flg=1,d1=getd(A[x],b);
	if(flg)return (d1+d)*V[y]>=d2*V[x]&&(d2+d)*V[x]>=d1*V[y];
	return d1*V[y]<=d2*V[x]&&(d2+d)*V[x]<=(d1+d)*V[y]||d2*V[x]<=d1*V[y]&&(d1+d)*V[y]<=(d2+d)*V[x];
}
int main(){
	LL _,i,j,x,y,z;
	x=0;j=2;
	rep(i,3,200000){
		if(i>j)j<<=1,++x;
		 lg[i]=x;
	}
	for(_=read();_--;){
		n=read();
		memset(he,0,sizeof he);tot=1;
		rep(i,2,n){
			x=read();y=read();z=read();
			add(x,y,z);add(y,x,z);
		}
		id=0;DFS(1,0);
		per(i,id,1){
			Min[i][0]=phi[i];
			for(j=1;i+(1<<j)-1<=id;++j)
				Min[i][j]=les(Min[i][j-1],Min[i+(1<<j-1)][j-1]);
		}
		m=read();ans=0;
		rep(i,1,m){
			A[i]=read();B[i]=read();V[i]=read();
			per(j,i-1,1)ans+=check(i,j);
		}
		printf("%d\n",ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值