LCA 在线倍增算法 配题(HDU 2585)

LCA:最近公共祖先。

算法:在线倍增算法,将问题转化为RMQ问题(序列极值问题)使用ST算法进行求解,ST算法的思想是两两比较,在两两比较的基础上四四比较,在四四比较的基础上八八比较(二进制的思想)。时间复杂度O\left ( nlogn \right )

本来是做的HDU 4547 但是不知道为啥就是AC不了,很难受。所以改为这个题目。(有点莫名其妙)也同时附上4547的代码供一起讨论。

配题:HDU 2585

题意:n个村庄,之间都是绝对路径,给出一些列查询,输出两个村庄之间的距离。可以用floyd最短路,但是会超时,所以此时可以使用LCA在线算法解决该问题,因为是只有一条路径。

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<cstdio>
using namespace std;
const int maxn = 40005;
int n, m;
struct NODE
{
	int v;
	int w;
};
vector<NODE>graph[maxn];
int dis[maxn];
int depth[maxn*2];
int dp[maxn*2][20];
bool vis[maxn];
int fst[maxn];
int ver[maxn*2];
int tot; 
void lca_dfs(int cur_node, int deep)
{
	vis[cur_node] = true;
	fst[cur_node] = ++tot;
	ver[tot] = cur_node;
	depth[tot] = deep;
	for (int i = 0; i < graph[cur_node].size(); i++)
	{
		int next_node = graph[cur_node][i].v;
		int w = graph[cur_node][i].w;
		if (vis[next_node]) continue;
		dis[next_node] = dis[cur_node] + w;
		lca_dfs(next_node, deep+1);
		depth[++tot] = deep;
		ver[tot] = cur_node;
	}
}

int MIN(int a, int b)
{
	if (depth[a] < depth[b])
	{
		return a;
	}
	else
	{
		return b;
	}
}

void lca_st()
{
	for (int i = 1; i <= tot; i++)
	{
		dp[i][0] = i;
	}
	
	for (int j = 1; (1<<j) <= tot; j++)
	{
		for (int i = 1; i + (1<<j) - 1 <= tot; i++)
		{
			dp[i][j] = MIN(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
		}
	}
}

int lca_query(int st, int ed)
{
	st = fst[st];
	ed = fst[ed];
	if (st > ed) swap(st, ed);
	int k = (int)log2(ed - st + 1);
	return ver[MIN(dp[st][k], dp[ed - (1<<k) + 1][k])];
}

int main()
{
	int T;
	cin>> T;
	while (T--)
	{
		tot = 0;
		cin>> n>> m;
		for (int i = 1; i <= n; i++)
		{
			graph[i].clear();
		}
		memset(vis, false, sizeof(vis));
		for (int i = 1; i <= n-1; i++)
		{
			int a, b, w;
			struct NODE node;
			scanf("%d %d %d", &a, &b, &w);
			node.v = b;
			node.w = w;
			graph[a].push_back(node);
			node.v = a;
			graph[b].push_back(node);
		}
		dis[1] = 0;
		lca_dfs(1, 1);
		lca_st();
		for (int i = 1; i <= m; i++)
		{
			int a, b;
			scanf("%d %d", &a, &b);
			int lca_id = lca_query(a, b);
			cout<< dis[a] + dis[b] - 2*dis[lca_id]<< endl;
		}
	}
	return 0;
}

附件:HDU 4547(中文题意),疯狂WA的代码,很难受,望指教。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
const int maxN = 100005;

vector<int>graph[maxN];
map<string, int>maplist;
int N, M;
bool degree[maxN];
int fst[maxN], depth[maxN*2], tot;
bool vis[maxN];
int dp[maxN*2][20];
int cnt;

int MIN(const int a, const int b)
{
    if (depth[a] < depth[b]) return a;
    else return b;
}

void lca_dfs(int cur_node, int deep)
{
    vis[cur_node] = true;
    fst[cur_node] = ++tot;
    depth[tot] = deep;
    
    for (int i = 0; i < graph[cur_node].size(); i++)
    {
        int next_node = graph[cur_node][i];
        if (vis[next_node]) continue;
        lca_dfs(next_node, deep + 1);
        depth[++tot] = deep;
    }
}

void RMQ()
{
    for (int i = 1; i <= tot; i++)
    {
        dp[i][0] = i;
    }
    for (int j = 1; (1 << j) <= tot; j++)
    {
        for (int i = 1; i + (1 << j) - 1 <= tot; i++)
        {
            dp[i][j] = MIN(dp[i][j-1], dp[i + (1<<j)][j-1]);
        }
    }
}

int query_RMQ(int st, int ed)
{
    if (st > ed)
    {
        swap(st, ed);
    }
    int k = (int)log2(ed - st + 1);
    return MIN(dp[st][k], dp[ed - (1<<k) + 1][k]);
}
int main()
{
    int T;
    cin>> T;
    while (T--)
    {
        int root;
        tot = 0;
        cnt = 0;
        
        scanf("%d %d", &N, &M);
        maplist.clear();
        memset(vis, false, sizeof(vis));
        memset(degree, false, sizeof(degree));
        
        for (int i = 0; i <= N ; i++)
        {
            graph[i].clear();
        }
        
        for (int i = 1; i <= N-1; i++)
        {
            char a[45], b[45];
            scanf("%s %s", a, b);
            if (!maplist[a]) maplist[a] = ++cnt;
            if (!maplist[b]) maplist[b] = ++cnt;
            graph[maplist[b]].push_back(maplist[a]);
            degree[maplist[a]] = true;
        }
        
        for (int i = 1; i <= cnt; i++)
        {
            if (degree[i] == false)
            {
                root = i;
                break;
            }
        }
        
        lca_dfs(root, 1);
        RMQ();
        for (int i = 1; i <= M; i++)
        {
            char a[45], b[45];
            scanf("%s %s", a, b); 
            int u = fst[maplist[a]];
            int v = fst[maplist[b]];
            
            if (N == 1 || u == v)
            {
                cout<< 0<< endl;
                continue;
            }
            int lca_id = query_RMQ(u, v);
            cout<< depth[u] - depth[lca_id] + (v != lca_id)<< endl;
        }
    }
    return 0;
}
 
发布了331 篇原创文章 · 获赞 135 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/Triple_WDF/article/details/102697208