基於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;
}