LCA【SP913】Qtree - Query on a tree II
2018-10-20 20:38
295 查看
Description
给定一棵n个点的树,边具有边权。要求作以下操作:
DIST a b 询问点a至点b路径上的边权之和
KTH a b k 询问点a至点b有向路径上的第k个点的编号
有多组测试数据,每组数据以DONE结尾。
Input
第一组数据包含一个整数\(T\),代表有\(T\)组测试数据。\(1\leq T \leq 25\)
对每一组测试数据:
- 第一行一个整数\(N(n \leq 10000)\)
- 接下来有\(N-1\)行,每一行描述树上的一条边\(a,b,c( c\leq 100000)\)
- 接下来几行操作包括\(DIST \ a \ b\),\(KTH \ a \ b \ k\)
- 以\(DONE\)结尾
Output
对于每一个\(DIST\)和\(KTH\)询问输出一行.
很明显,LCA,但是难点就在于如何求出\(KTH\)对于的答案.
首先会存在两种情况
一. \(k \leq depth[x]-depth[lca_{x,y}]+1\)
很明显,这时第\(k\)个点必然在于\(x->lca_{x,y}\)的路径上,我们只需要知道其深度即可倍增求取.
可求其深度为\(depth[x]-k+1\)
二. \(k > depth[x]-depth[lca_{x,y}]+1\)
这时,第\(k\)个点必然存在于\(y->lca_{x,y}\)的路径上,但是如何求其深度却是一个问题.
先设\(ans\)为第\(k\)个点的深度.
我们可以得到的信息是\(k\)必须要在\(y->lca_{x,y}\),
所以新的深度至少必须为\(k-(depth[x]-depth[lca_{x,y}]+1)\)
但是由于我们的\(lca_{x,y}\)不一定为\(1\)(这里我以\(1\)为根)
所以原式子还需要加上一个\(depth[lca_{x,y}]\)。
因此可以得到这样一个式子
\[
ans=k-depth[x]+2*depth[lca_{x,y}]-1;
\]
知道深度之后,直接倍增跳即可.
代码
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> #define clear(a) memset(a,0,sizeof a) #define N 10008 #define R register using namespace std; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } int T; int n,head ,tot; struct cod{int u,v,w;}edge[N<<2]; inline void add(int x,int y,int z) { edge[++tot].u=head[x]; edge[tot].v=y; edge[tot].w=z; head[x]=tot; } int depth ,f [21],dis ; void dfs(int u,int fa,int dist) { f[u][0]=fa;dis[u]=dis[fa]+dist;depth[u]=depth[fa]+1; for(R int i=1;(1<<i)<=depth[u];i++) f[u][i]=f[f[u][i-1]][i-1]; for(R int i=head[u];i;i=edge[i].u) { if(edge[i].v==fa)continue; dfs(edge[i].v,u,edge[i].w); } } inline int lca(int x,int y) { if(depth[x]>depth[y])swap(x,y); for(R int i=17;i>=0;i--) if(depth[x]+(1<<i)<=depth[y]) y=f[y][i]; if(x==y)return y; for(R int i=17;i>=0;i--) { if(f[x][i]==f[y][i])continue; x=f[x][i],y=f[y][i]; } return f[x][0]; } char s[108]; inline int query(int x,int y,int k) { R int la=lca(x,y); if(depth[x]-depth[la]+1>=k) { R int ans=depth[x]-k+1; for(R int i=17;i>=0;i--) { if(depth[x]-ans>=(1<<i)) x=f[x][i]; } return x; } else { R int ans=depth[la]*2+k-depth[x]-1; for(R int i=17;i>=0;i--) if((1<<i)<=depth[y]-ans) y=f[y][i]; return y; } } int main() { in(T); for(;T;T--) { in(n); tot=0;clear(head),clear(dis),clear(f);clear(depth); for(R int i=1,x,y,z;i<n;i++) { in(x),in(y),in(z); add(x,y,z);add(y,x,z); } dfs(1,0,0); for(R int x,y,la,k;;) { scanf("%s",s+1); if(s[2]=='O')break; if(s[2]=='I') { in(x),in(y); la=lca(x,y); printf("%d\n",dis[x]+dis[y]-2*dis[la]); } else { in(x),in(y),in(k); printf("%d\n",query(x,y,k)); } } } }
相关文章推荐
- 【SPOJ】913 Query on a tree II QTREE系列之2【LCA】
- SPOJ 913 QTREE系列- Query on a tree II (倍增LCA)
- LCA SP913 QTREE2 - Query on a tree II
- spoj 913 Query on a tree II (倍增lca)
- SPOJ-QTREE2 Query on a tree II(暴力+LCA)
- 【SPOJ QTREE2】QTREE2 - Query on a tree II(LCA)
- Spoj Query on a tree II (LCA)
- SPOJ Query on a tree II (倍增LCA)
- SPOJ Query on a tree II (树剖||倍增LCA)(占位)
- SPOJ QTREE2 Query on a tree II(LCA)
- SPOJ Query on a tree II (倍增LCA)
- SPOJ QTREE2 Query on a tree II 倍增lca
- SPOJ QTREE2 Query on a tree II (倍增LCA)
- SPOJ QTREE2 Query on a tree II
- SPOJ QTREE2 Query on a tree II
- 树链剖分【p4114】Qtree-Query on a tree I
- [SPOJ375] QTREE - Query on a tree
- SPOJ - QTREE Query on a tree(树剖)
- 动态树LCT(SPOJ QTREE2 - Query on a tree II)
- SPOJ 375 Query on a tree(树链剖分)(QTREE)