LCA(最近公共祖先)学习、

基於Tarjan資料:傳送門

                            傳送門

入門題: POJ 1330




codeVS 2370

第一次见到这种代码风格, 学习了...

#include <cstring>
#include <cstdio>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;
#define pb push_back
#define REP(i, x, n)	for(int i = x; i < n; ++i)
const int qq = 50000 + 10, maxm = 75005;
typedef long long ll;
vector<int> G[qq], dist[qq], u[qq], f[qq];
bool vis[qq], vt[qq];
int fa[qq], w[maxm], n;
ll anc[qq];
int Find(int x){
	return fa[x] == 0 ? x : fa[x] = Find(fa[x]);
}
inline void uni(int x, int y){
	int b = Find(y);
	if(b != x)	fa[b] = x;
}
void Tarjan(int x, ll k){
	anc[x] = k;
	for(int i = 0; i < (int)G[x].size(); ++i)if(!vt[G[x][i]]){
		int v = G[x][i];
		vt[v] = true;
		Tarjan(v, k + dist[x][i]);
		uni(x, v);
	}
	vis[x] = true;
	for(int i = 0; i < (int)u[x].size(); ++i)if(vis[u[x][i]]){
		w[f[x][i]] = anc[x] + anc[u[x][i]] - 2 * anc[Find(u[x][i])];
	}
}

int main(){
	scanf("%d", &n);
	int a, b, c, m;
	for(int i = 1; i < n; ++i){
		scanf("%d%d%d", &a, &b, &c);
		a++, b++;
		G[a].pb(b), dist[a].pb(c);
		G[b].pb(a), dist[b].pb(c);
	}
	scanf("%d", &m);
	for(int i = 1; i <= m; ++i){
		scanf("%d%d", &a, &b), a++, b++;
		u[a].pb(b), u[b].pb(a);
		f[a].pb(i), f[b].pb(i);
	}
	vt[1] = true;
	for(int i = 1; i <= m; ++i)
		printf("%d\n", w[i]);
	return 0;
}



HDU2874

这题好烦, 无限MLE, 最初直接用并查集判断两个点直接是否有最短路径... 后面借鉴了这种方法...

不能用vector存图.

#include <cstring>
#include <cstdio>
#include <cmath>
#include <iostream>

using namespace std;
const int qq = 10005, MAXN = 1000005, N = 20005;
int Ghead[qq], Rhead[qq];
struct Edge{
	int to, dist, next;
}edge[N];
struct Relation{
	int link, id, next;
}rela[MAXN * 2];
int fa[qq];
int vis[qq];
int anc[qq], w[MAXN];
int n, m, q;
int Gtop, Rtop;

int Find(int x){
	return fa[x] == -1 ? x : fa[x] = Find(fa[x]);
}
void Union(int x, int y){
	int b = Find(y);
	if(x != b)	fa[b] = x;
}
void AddG(int u, int v, int dist){
	edge[Gtop].to = v, edge[Gtop].dist = dist, edge[Gtop].next = Ghead[u], Ghead[u] = Gtop++;
	edge[Gtop].to = u, edge[Gtop].dist = dist, edge[Gtop].next = Ghead[v], Ghead[v] = Gtop++;
}	
void AddR(int u, int v, int id){
	rela[Rtop].link = v, rela[Rtop].id = id, rela[Rtop].next = Rhead[u], Rhead[u] = Rtop++;
	rela[Rtop].link = u, rela[Rtop].id = id, rela[Rtop].next = Rhead[v], Rhead[v] = Rtop++;
}	
void Tarjan(int x, int c, int root){
	int i, y;
	anc[x] = c;
	fa[x] = -1;
	vis[x] = root;
	for(i = Ghead[x]; i != -1; i = edge[i].next)if(vis[edge[i].to] == -1){
		y = edge[i].to;
		Tarjan(y, c + edge[i].dist, root);
		fa[y] = x;
	}
	for(i = Rhead[x]; i != -1; i = rela[i].next)if(vis[rela[i].link] == root){
		w[rela[i].id] = anc[x] + anc[rela[i].link] - 2ll * anc[Find(rela[i].link)];
	}
}
int main(){
	while(scanf("%d%d%d", &n, &m, &q) != EOF){
		Gtop = Rtop = 0;
		memset(Ghead, -1, sizeof(Ghead));
		memset(Rhead, -1, sizeof(Rhead));
		int a, b, c;
		for(int i = 0; i < m; ++i){
			scanf("%d%d%d", &a, &b, &c);
			AddG(a, b, c);
		}
		memset(w, -1, sizeof(w));
		for(int i = 1; i <= q; ++i){
			scanf("%d%d", &a, &b);
			if(a == b){
				w[i] = 0;
			}else{
				AddR(a, b, i);
			}
		}
		memset(vis, -1, sizeof(vis));
		for(int i = 1; i <= n; ++i)
			if(vis[i] == -1)	Tarjan(i, 0, i);
		for(int i = 1; i <= q; ++i)
			if(w[i] == -1){
				puts("Not connected");
			}else{
				printf("%d\n", w[i]);
			}
	}
	return 0;
}



POJ 1986

precisely one path (sequence of roads) links every pair of farms

这句话说明每两个农场之间只有唯一的一条路, 那么它显然是一颗树

涨知识了

用vector很慢会超时, 果然越底层的东西越快

#include <cstring>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
#define qq 40010
#define pb push_back
#define REP(i, x, n)	for(int i = x; i < n; ++i)
struct Edge{
	int to, dist, next;
}edge[qq * 3], tmp;
struct Query{
	int to, id, next;
}query[qq], temp;
int Ghead[qq], Qhead[qq];
int Gtop, Qtop;
bool vis[qq];
int anc[qq], w[qq], fa[qq];
int n, m;
void Gadd(int u, int v, int c){
	edge[Gtop].to = v;
	edge[Gtop].dist = c;
	edge[Gtop].next = Ghead[u];
	Ghead[u] = Gtop++;
}
void Qadd(int u, int v, int c){
	query[Qtop].to = v;
	query[Qtop].id = c;
	query[Qtop].next = Qhead[u];
	Qhead[u] = Qtop++;
}
int Find(int x){
	return fa[x] == -1 ? x : fa[x] = Find(fa[x]);
}
void Unoin(int x, int y){
	int b = Find(y);
	if(b != x)	fa[b] = x;
}
void Tarjan(int x, int c){
	anc[x] = c;
	vis[x] = true;
	fa[x] = -1;
	for(int i = Ghead[x]; i != -1; i = edge[i].next)if(!vis[edge[i].to]){
		int y = edge[i].to;
		Tarjan(y, c + edge[i].dist);
		Unoin(x, y);
	}
	for(int i = Qhead[x]; i != -1; i = query[i].next)if(vis[query[i].to]){
		w[query[i].id] = anc[x] + anc[query[i].to] - 2 * anc[Find(query[i].to)];
	}
}
int main(){
	memset(Ghead, -1, sizeof(Ghead));
	memset(Qhead, -1, sizeof(Qhead));
	Gtop = Qtop = 0;
	scanf("%d%d", &n, &m);
	int a, b, c;
	char st[15];
	REP(i, 0, m){
		scanf("%d%d%d%s", &a, &b, &c, st);
		Gadd(a, b, c);
		Gadd(b, a, c);
	}
	int k;	scanf("%d", &k);
	REP(i, 0, k){
		scanf("%d%d", &a, &b);
		Qadd(a, b, i);
		Qadd(b, a, i);
	}
	Tarjan(1, 0);
	REP(i, 0, k){
		printf("%d\n", w[i]);
	}
	return 0;
}



POJ 1470

这题很奇怪, 居然卡输入...      按行读入一直T

最后借用这种读入

通过这题我发现在Tarjan算法里面的vis[x] = true 这条语句其实是有内涵的

放在函数开始那么每一句询问可能会被查询两次

如果放在深搜结束, 那么每一个点都准确的只查询一次

#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>

using namespace std;
#define qq 909
#define pb push_back
#define mk make_pair
#define REP(i, x, n)	for(int i = x; i < n; ++i)
#define pill pair<int, int>
int Ghead[qq], Qhead[qq];
bool vis[qq];
bool root[qq];
int fa[qq], res[qq];
int n, m;
char st[10000];
map<pill, bool> mp;
struct Edge{
	int to, next;
}edge[qq];
struct Query{
	int to, next;
}qury[500005];
int Gtop, Qtop;
void Gadd(int u, int v){
	edge[Gtop].to = v;
	edge[Gtop].next = Ghead[u];
	Ghead[u] = Gtop++;
}
void Qadd(int u, int v){
	qury[Qtop].to = v;
	qury[Qtop].next = Qhead[u];
	Qhead[u] = Qtop++;
}
int Find(int x){
	return fa[x] == -1 ? x : fa[x] = Find(fa[x]);
}
void Union(int x, int y){
	int b = Find(y);
	if(b != x)	fa[b] = x;
}
void Tarjan(int x){
	fa[x] = -1;
	for(int i = Ghead[x]; i != -1; i = edge[i].next)if(!vis[edge[i].to]){
		int y = edge[i].to;
		Tarjan(y);
		Union(x, y);
	}
	vis[x] = true;
	for(int i = Qhead[x]; i != -1; i = qury[i].next)if(vis[qury[i].to]){
		int y = qury[i].to;
		res[Find(y)]++;
	}
}
int main(){
	int t;
	while(scanf("%d", &t) != EOF){
		Qtop = Gtop = 0;
		memset(Qhead, -1, sizeof(Qhead));
		memset(Ghead, -1, sizeof(Ghead));
		memset(vis, false, sizeof(vis));
		memset(root, false, sizeof(root));
		memset(res, 0, sizeof(res));
		mp.clear();
		int num, vt;
		REP(i, 0, t){
			scanf("%d:(%d)", &vt, &num);
			int x;
			while(num--){
				scanf("%d", &x);
				root[x] = true;
				Gadd(vt, x);
			}
		}
		int k;	scanf("%d", &k);
		int a, b;
		for(int i = 0; i < k; ++i){
			scanf(" (%d %d) ", &a, &b);
			if(a == b){
				res[a]++;
				continue;
			}
			Qadd(a, b);
			Qadd(b, a);
		}
		for(int i = 1; i <= t; ++i)
			if(root[i] == false){
				Tarjan(i);
				break;
			}
		for(int i = 1; i <= t; ++i)if(res[i]){
			printf("%d:%d\n", i, res[i]);
		}
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值