第一次做LCA的题,梁神说Tarjan和RMQ的模版都要有,然后我就顺便找了一下。题意很简单,就是给一些边,边上有权值,然后询问两点之间的最短距离。貌似找最近公共祖先的模版要改一些地方,我直接就在网上找新模版了,从这个题我知道STL的vector有多慢了,用前向星实现的Tarjan算法比STL快了近一秒,伤不起,打算以后就用前向星了,把模版贴在这里吧。
Tarjan
#include<iostream>
#include<cmath>
using namespace std;
const int maxn=40001;
const int maxk=10001;
struct Edge
{
int v,w,next;
}g[maxn*2],q[maxk*2];
int headg[maxn],headq[maxn],parent[maxn],dis[maxn],pos1,pos2,n,m,k,a,b,c;
char d[10];
int ans[maxk];
bool vis[maxn];
void init()
{
memset(headq,0,sizeof(int)*(1+n));
memset(headg,0,sizeof(int)*(1+n));
memset(vis,0,sizeof(bool)*(1+n));
memset(parent,-1,sizeof(int)*(1+n));
pos1=pos2=1;
}
void add(int a,int b,int c)
{
g[pos1].next=headg[a];
g[pos1].v=b;
g[pos1].w=c;
headg[a]=pos1++;
}
void add_2(int a,int b,int c)
{
q[pos2].next=headq[a];
q[pos2].v=b;
q[pos2].w=c;
headq[a]=pos2++;
}
int find(int a)
{
if(parent[a]==-1)
return a;
return parent[a]=find(parent[a]);
}
void tarjan(int u,int now_dis)
{
dis[u]=now_dis;
vis[u]=1;
int v,w;
for(int i=headq[u];i;i=q[i].next)
{
v=q[i].v,w=q[i].w;
if(vis[v])
{
ans[w]=dis[u]+dis[v]-2*dis[find(v)];
}
}
for(int i=headg[u];i;i=g[i].next)
{
v=g[i].v,w=g[i].w;
if(!vis[v])
{
tarjan(v,now_dis+w);
parent[v]=u;
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=0;i<m;i++)
{
scanf("%d%d%d%s",&a,&b,&c,d);
add(a,b,c);
add(b,a,c);
}
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
scanf("%d%d",&a,&b);
add_2(a,b,i);
add_2(b,a,i);
}
tarjan(1,0);
for(int i=1;i<=k;i++)
printf("%d\n",ans[i]);
}
}
RMQ
#include<stdio.h>
#include<string.h>
#include<math.h>
#include <iostream>
using namespace std;
#define MAXN 40005
#define MAXM 80005
int n, m, q;
struct EDGE
{
int v, next, w;
}edge[MAXM];
int head[MAXN], e;
int index, tmpdfn;
int f[2 * MAXN], id[MAXN], vis[MAXN], pos[MAXN], dis[MAXN];
int mi[2 * MAXN][18];
void init()
{
memset(head, -1, sizeof(head));
e = 0;
index = tmpdfn = 0;
memset(vis, 0, sizeof(vis));
dis[1] = 0;
}
void add(int u, int v, int w)
{
edge[e].v = v;
edge[e].w = w;
edge[e].next = head[u];
head[u] = e++;
}
void dfs(int u)
{
vis[u] = 1;
int tmp = ++tmpdfn;
f[++index] = tmp;
id[tmp] = u;
pos[u] = index;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(!vis[v])
{
dis[v] = dis[u] + edge[i].w;
dfs(v);
f[++index] = tmp;
}
}
}
void rmqinit(int n, int *w)
{
for(int i = 1; i <= n; i++) mi[i][0] = w[i];
int m = (int)(log(n * 1.0) / log(2.0));
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
{
mi[j][i] = mi[j][i - 1];
if(j + (1 << (i - 1)) <= n) mi[j][i] = min(mi[j][i], mi[j + (1 << (i - 1))][i - 1]);
}
}
int rmqmin(int l,int r)
{
int m = (int)(log((r - l + 1) * 1.0) / log(2.0));
return min(mi[l][m] , mi[r - (1 << m) + 1][m]);
}
int LCA(int l, int r)
{
if(pos[l] > pos[r]) swap(l, r);
int ans = rmqmin(pos[l], pos[r]);
return id[ans];
}
int main()
{
scanf("%d%d", &n, &m);
int u, v, w, l, r;
init();
while(m--)
{
scanf("%d%d%d%*s", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
dfs(1);
rmqinit(index, f);
scanf("%d", &q);
while(q--)
{
scanf("%d%d", &l, &r);
printf("%d\n", dis[l] + dis[r] - 2 * dis[LCA(l, r)]);
}
return 0;
}