原理:
void dfs(int k,int d,long long sum)
{
cost[k]=sum;
pos[k]=++tot; ///记录第一次出现的时间戳
F[tot]=k; ///记录欧拉序列
rmq[tot]=d;///记录该时间戳深度
vis[k]=1;
for(int i=fir[k];~i;i=nex[i])
{
int e=v[i];
if(!vis[e])
{
dfs(e,d+1,sum+w[i]);
F[++tot]=k; ///继续记录访问时间戳,那么此时就相当于在每个子节点中插入了父节点,
///在利用pos下标查询RMQ时父节点的信息就卡在了两者之间
rmq[tot]=d;
}
}
}
ST(来源 :kuangbin模板):
int F[maxn],pos[maxn],tot;
long long cost[maxn];
int rmq[maxn];//rmq数组,就是欧拉序列对应的深度序列
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)//查询[a,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];
}
} st;
初始化:
void LCA_init()
{
memset(vis,0,sizeof vis);
for(int i=1; i<=n; i++)
{
if(!vis[i])
{
dfs(i,1,0);
}
}
st.init(tot);
}
查询部分:
long long Query(int s,int t)
{
int lca=F[ st.query(pos[s],pos[t]) ];
return cost[s]+cost[t]-2*cost[lca];
}
HDU 2586 How far away ?
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 80004
int fir[maxn],nex[maxn],v[maxn],w[maxn],e_max;
int pos[2*maxn],T[2*maxn],tot;
long long cost[maxn];
int rmq[2*maxn];//rmq数组,就是欧拉序列对应的深度序列
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)//查询[a,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];
}
}LCA;
void init()
{
memset(fir,-1,sizeof fir);
e_max=0;
tot=1;
}
void add_edge(int s,int t,int c)
{
int e=e_max++;
v[e]=t;
w[e]=c;
nex[e]=fir[s];
fir[s]=e;
}
void dfs(int k,int pre,int d,long long sum)
{
cost[k]=sum;
pos[k]=tot;
T[tot]=k;
rmq[tot++]=d;
for(int i=fir[k]; ~i; i=nex[i])
{
int e=v[i];
if(e==pre) continue;
dfs(e,k,d+1,sum+w[i]);
T[tot]=k;
rmq[tot++]=d;
}
}
void LCA_init()
{
dfs(1,-1,1,0);
LCA.init(tot-1);
}
long long Query(int s,int t)
{
int lca=T[LCA.query(pos[s],pos[t])];
return cost[s]+cost[t]-2*cost[lca];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<n; i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
}
LCA_init();
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
long long ans=Query(l,r);
printf("%lld\n",ans);
}
}
return 0;
}
POJ 1986 Distance Queries
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 80004
int x[maxn],y[maxn],c[maxn],e[maxn],s[maxn],pos[2*maxn];
int fir[maxn],nex[maxn],v[maxn],w[maxn],e_max,tot;
long long cost[maxn];
int rmq[2*maxn],F[2*maxn];//rmq数组,就是欧拉序列对应的深度序列
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)//查询[a,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];
}
} LCA;
void init()
{
memset(fir,-1,sizeof fir);
e_max=0;
tot=1;
}
void add_edge(int s,int t,int c)
{
int e=e_max++;
v[e]=t;
w[e]=c;
nex[e]=fir[s];
fir[s]=e;
}
void dfs(int k,int pre,int d,long long sum)
{
pos[k]=tot;
rmq[tot]=d;
F[tot++]=k;
cost[k]=sum;
for(int i=fir[k]; ~i; i=nex[i])
{
int e=v[i];
if(e!=pre)
{
dfs(e,k,d+1,sum+w[i]);
rmq[tot]=d;
F[tot++]=k;
}
}
}
void LCA_init()
{
dfs(1,-1,1,0);
LCA.init(tot-1);
}
long long Query(int s,int t)
{
int lca=F[LCA.query(pos[s],pos[t])];
return cost[s]+cost[t]-2*cost[lca];
}
bool cmp(int a,int b)
{
return c[a]<c[b];
}
int root(int x)
{
return s[x]==x?x:s[x]=root(s[x]);
}
int n,m;
void build()
{
for(int i=0; i<=n; i++) s[i]=i;
sort(e+1,e+m+1,cmp);
for(int i=1; i<=m; i++)
{
int r=e[i];
int _x=root(x[r]);
int _y=root(y[r]);
if(_x!=_y)
{
s[_x]=_y;
add_edge(x[r],y[r],c[r]);
add_edge(y[r],x[r],c[r]);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=1; i<=m; i++)
{
char str[5];
scanf("%d%d%d%s",&x[i],&y[i],&c[i],str);
e[i]=i;
}
build();
LCA_init();
int q;
scanf("%d",&q);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",Query(l,r));
}
}
return 0;
}
HDU 2874 Connections between cities
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 40004
int x[maxn],y[maxn],c[maxn],e[maxn];
int vis[maxn];
int fir[maxn],nex[maxn],v[maxn],w[maxn],e_max,s[maxn];
int F[maxn],pos[maxn],tot;
long long cost[maxn];
int rmq[maxn];//rmq数组,就是欧拉序列对应的深度序列
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)//查询[a,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];
}
} st;
void init()
{
e_max=0;
tot=0;
memset(fir,-1,sizeof fir);
}
void add_edge(int s,int t,int c)
{
int e=e_max++;
v[e]=t;
w[e]=c;
nex[e]=fir[s];
fir[s]=e;
}
bool cmp(int a,int b)
{
return c[a]<c[b];
}
int root(int x)
{
return s[x]==x?x:s[x]=root(s[x]);
}
int n,m,q;
void build()
{
sort(e,e+m,cmp);
for(int i=0; i<=n; i++) s[i]=i;
for(int i=0; i<m; i++)
{
int r=e[i];
int _x=root(x[r]);
int _y=root(y[r]);
if(_x!=_y)
{
s[_x]=_y;
add_edge(x[r],y[r],c[r]);
add_edge(y[r],x[r],c[r]);
}
}
}
void dfs(int k,int d,long long sum)
{
cost[k]=sum;
pos[k]=++tot;
F[tot]=k;
rmq[tot]=d;
vis[k]=1;
for(int i=fir[k];~i;i=nex[i])
{
int e=v[i];
if(!vis[e])
{
dfs(e,d+1,sum+w[i]);
F[++tot]=k;
rmq[tot]=d;
}
}
}
void LCA_init()
{
memset(vis,0,sizeof vis);
for(int i=1; i<=n; i++)
{
if(!vis[i])
{
dfs(i,1,0);
}
}
st.init(tot);
}
long long Query(int s,int t)
{
int lca=F[ st.query(pos[s],pos[t]) ];
return cost[s]+cost[t]-2*cost[lca];
}
int main()
{
while(scanf("%d%d%d",&n,&m,&q)!=EOF)
{
init();
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&x[i],&y[i],&c[i]);
e[i]=i;
}
build();
LCA_init();
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
if(root(l)!=root(r))
printf("Not connected\n");
else printf("%lld\n",Query(l,r));
}
}
return 0;
}