装逼的英语解释了好多意义:
思想:dp【i】【j】表示从i开始的,长度为2^j的一段元素的最小值
点我就搞懂了RMQ
例题:网络赛签到题:HDOJ5443TheWaterProblem
http://www.cnblogs.com/ylfdrib/archive/2010/11/03/1867901.html
http://ayzk.wordpress.com.cn/archives/14
例题:
POJ 1330 bin神模板过之
HDOJ 2586
变化:题中树上边有权值
代码改动:
《1》再定义一个数组,dir【】表示该点离根的距离
《2》addedge在加边时需要多添加一个参数:两点距离
《3》lca求出来的是位置坐标
《4》在dfs中需要记录节点离根的距离即:dir【v】=dir【u】+edge【】。cost
《5》最后答案ans=dir【u】+dir【v】-dir【lca】:自己画图就明白了的
贴上我bin的模板:可以裸过POJ 1330
int rmq[2*maxn]; struct ST{ int mm[2*maxn]; int dp[2*maxn][20]; void init(int n){ mm[0]=-1; for(int i=1;i<=n;i++){ mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; dp[i][0]=i; } for(int j=1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1]; } int query(int a,int b){ if (a>b) swap(a,b); int k=mm[b-a+1]; return rmq[dp[a][k]]<=rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k]; } }; struct Edge{ int to,Next; }edge[maxn*2]; int tot,head[maxn]; int F[maxn*2]; int P[maxn]; int cnt; ST st; void init(){ tot=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v){ edge[tot].to=v; edge[tot].Next=head[u]; head[u]=tot++; } void dfs(int u,int pre,int dep){ F[++cnt]=u; rmq[cnt]=dep; P[u]=cnt; for(int i=head[u];i!=-1;i=edge[i].Next){ int v=edge[i].to; if (v==pre) continue; dfs(v,u,dep+1); F[++cnt]=u; rmq[cnt]=dep; } } void LCA_init(int root,int node_num){ cnt=0; dfs(root,root,0); st.init(2*node_num-1); } int query_lca(int u,int v){ return F[st.query(P[u],P[v])]; } bool flag[maxn]; int main(){ //input; int T,N,u,v; scanf("%d",&T); while(T--){ scanf("%d",&N); init(); memset(flag,false,sizeof(flag)); for(int i=1;i<N;i++){ scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); flag[v]=true; } int root; for(int i=1;i<=N;i++) if (!flag[i]){ root=i; break; } LCA_init(root,N); scanf("%d%d",&u,&v); printf("%d\n",query_lca(u,v)); } return 0; }