题目描述 Description
某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。
假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。
你的任务是帮助该商人计算一下他的最短旅行时间。
输入描述 Input Description
输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=a, b<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。
输出描述 Output Description
在输出文件中输出该商人旅行的最短时间。
LCA问题,可以转化为RMQ问题
dep[]表示节点在树中的深度
F是欧拉序列,B是欧拉序列节点对应的深度
pos[]表示节点第一次在欧拉序列中出现的位置
LCA(T,u,v)=F[RMQ(B,pos[u],pos[v])]
这里RMQ要返回坐标,而不是具体值,但本题不需要,本题只要得到LCA的深度即可,直接让RMQ返回具体值即可,所求深度就是这个返回值
最小值也可以用线段树维护
#include<iostream> #include<cstring> using namespace std; ; struct node{ int l,r,mmin; }tree[*maxn]; struct edge{ int go,next; }e[*maxn]; ,count=,F[*maxn],B[*maxn],M,pos[maxn],v[maxn]; void add(int a,int b){ e[++ecount].go=b; e[ecount].next=end[a]; end[a]=ecount; } void buildTree(int f,int x,int d){ int go; dep[x]=d; F[++count]=x; B[count]=d; if(!v[x]){ pos[x]=count;v[x]=; } for(int i=end[x];i;i=e[i].next){ go=e[i].go; if(go!=f){ buildTree(x,go,d+); F[++count]=x; B[count]=d; } } } void init() { memset(end,,sizeof(end)); memset(v,,sizeof(v)); } void build(int o,int l,int r){ if(l==r){ tree[o].l=tree[o].r=l; tree[o].mmin=B[l]; return; } ; build(*o,l,m);build(*o+,m+,r); tree[o].l=l,tree[o].r=r; tree[o].mmin=min(tree[o*].mmin,tree[o*+].mmin); } int query(int o,int l,int r){ if(l<=tree[o].l&&tree[o].r<=r) return tree[o].mmin; ; <<; *o,l,r)); *o+,l,r)); return ans; } int main() { cin>>N; init(); int x,y; ;i<=N;i++){ cin>>x>>y; add(x,y),add(y,x); } buildTree(-,,); build(,,count); //for(int i=1;i<=count;i++) cout<<i<<"F:"<<F[i]<<endl; cin>>M; ,to; cin>>last; ;i<M;i++){ cin>>to; ans+=dep[last]+dep[to]-*B[query(,min(pos[last],pos[to]),max(pos[last],pos[to]))]; last=to; } cout<<ans; ; }