题意:
Problem Description
在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录。
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
Input
输入数据第一行包含一个整数T(T<=20),表示样例个数;
每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;
接下来N-1行每行两个目录名A B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。
最后M行每行两个目录名A B,表示询问将当前目录从A变成B最少要多少次CD操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;
接下来N-1行每行两个目录名A B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。
最后M行每行两个目录名A B,表示询问将当前目录从A变成B最少要多少次CD操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
Output
请输出每次询问的结果,每个查询的输出占一行。
Sample Input
2 3 1 B A C A B C 3 2 B A C B A C C A
Sample Output
2 1 2
解析:
错了一个下午,用各种姿势wa。
不知道为什么一定要按照问题的id去排最后的ans。
难道输出就不是有序的吗。。。
就算是这里的问题,st在线算法还是wa。。。无言以对,不知道什么数据卡了。
代码:
换了上一题的模板,稳多了,wa了两发是因为数组开小了(╯^╰)
ac:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
const int maxn = 100000 + 10;
vector<pair<int, int> > ansQue;
int ind[maxn];
map<string, int> mp;
int dis[maxn], vis[maxn], ancestor[maxn];
int ans[maxn];
struct Edge
{
int to, next;
int len;
} edge[maxn << 1];
int edgeNum;
int edgeHead[maxn << 1];
void addEdge(int fr, int to, int len)
{
edge[edgeNum].to = to;
edge[edgeNum].len = len;
edge[edgeNum].next = edgeHead[fr];
edgeHead[fr] = edgeNum++;
edge[edgeNum].to = fr;
edge[edgeNum].len = len;
edge[edgeNum].next = edgeHead[to];
edgeHead[to] = edgeNum++;
}
struct Query
{
int to, next;
int id;
} query[maxn << 1];
int queryNum;
int queryHead[maxn << 1];
void addQuery(int fr, int to, int id)
{
query[queryNum].to = to;
query[queryNum].id = id;
query[queryNum].next = queryHead[fr];
queryHead[fr] = queryNum++;
query[queryNum].to = fr;
query[queryNum].id = id;
query[queryNum].next = queryHead[to];
queryHead[to] = queryNum++;
}
int Find(int x)
{
if (ancestor[x] == x)
return x;
return ancestor[x] = Find(ancestor[x]);
}
void lca(int u, int dep, int rt)
{
ancestor[u] = u;
vis[u] = rt;
dis[u] = dep;
for (int i = edgeHead[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (vis[v] == -1)
{
lca(v, dep + edge[i].len, rt);
ancestor[v] = u;
}
}
for (int i = queryHead[u]; i != -1; i = query[i].next)
{
int v = query[i].to;
if (vis[v] == rt)
{
ans[query[i].id] = ancestor[Find(v)];
}
}
}
void init()
{
edgeNum = 0;
queryNum = 0;
memset(edgeHead, -1, sizeof(edgeHead));
memset(queryHead, -1, sizeof(queryHead));
memset(vis, -1, sizeof(vis));
memset(ans, -1, sizeof(ans));
memset(ind, 0, sizeof(ind));
ansQue.clear();
mp.clear();
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
int n, m;
scanf("%d%d", &n, &m);
init();
int tot = 1;
for (int i = 1; i < n; i++)
{
string a, b;
cin >> a >> b;
if (mp.find(a) == mp.end())
{
mp[a] = tot++;
}
if (mp.find(b) == mp.end())
{
mp[b] = tot++;
}
addEdge(mp[b], mp[a], 1);
ind[mp[a]]++;
}
for (int i = 0; i < m; i++)
{
string a, b;
cin >> a >> b;
ans[i] = -1;
addQuery(mp[a], mp[b], i);
ansQue.push_back(make_pair(mp[a], mp[b]));
}
int rt;
for (int i = 1; i <= n; i++)
{
if (!ind[i])
{
rt = i;
break;
}
}
lca(rt, 0, rt);
for (int i = 0; i < m; i++)
{
int fr = ansQue[i].first;
int to = ansQue[i].second;
if (fr == to)
{
printf("0\n");
}
else if (fr == ans[i])
{
printf("1\n");
}
else if (to == ans[i])
{
printf("%d\n", dis[fr] - dis[to]);
}
else
{
printf("%d\n", dis[fr] - dis[ans[i]] + 1);
}
}
}
return 0;
}
ac:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
///
int ans[maxn];
vector<pair<int, int> > ansQue;
struct Query
{
int to, id;
Query(){}
Query(int _to, int _id)
{
to = _to;
id = _id;
}
};
map<string, int> mp;
int step[maxn];
int n;
vector<int> edge[maxn];
vector<Query> query[maxn];
int inDegree[maxn];
int ancestor[maxn];
bool vis[maxn];
int fa[maxn];
int Rank[maxn];
void Init(int n)
{
mp.clear();
ansQue.clear();
for (int i = 1; i <= n; i++)
{
fa[i] = i;
Rank[i] = 0;
edge[i].clear();
query[i].clear();
}
memset(vis, false, sizeof(vis));
memset(inDegree, 0, sizeof(inDegree));
memset(ancestor, 0, sizeof(ancestor));
memset(step, 0, sizeof(step));
}
int Find(int x)
{
if (fa[x] != x)
fa[x] = Find(fa[x]);
return fa[x];
}
void Union(int u, int v)
{
int fau = Find(u);
int fav = Find(v);
if (fau == fav)
return;
if (Rank[fau] < Rank[fav])
{
fa[fau] = fav;
}
else
{
fa[fav] = fau;
if (Rank[fau] == Rank[fav])
Rank[fau]++;
}
}
void lca(int rt, int num)
{
//自成集合
step[rt] = num;
ancestor[rt] = rt;
int sz = edge[rt].size();
for (int i = 0; i < sz; i++)
{
int v = edge[rt][i];
lca(v, num + 1); //递归子树
Union(rt, v); //合并子树与根
ancestor[Find(v)] = rt; //子树祖先也指向根
}
vis[rt] = true;
sz = query[rt].size();
for (int i = 0; i < sz; i++)
{
int fr = rt;
int to = query[rt][i].to;
int id = query[rt][i].id;
if (vis[to])
{
///记录答案时必须要这样。。。否则wa到死。。。
///ps.I don't know why...
ans[id] = ancestor[Find(to)];
}
}
return;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
int n, m;
scanf("%d%d", &n, &m);
Init(n);
int tot = 1;
for (int i = 1; i < n; i++)
{
string a, b;
cin >> a >> b;
if (mp.find(a) == mp.end())
{
mp[a] = tot++;
}
if (mp.find(b) == mp.end())
{
mp[b] = tot++;
}
edge[mp[b]].push_back(mp[a]);
inDegree[mp[a]]++;
}
for (int i = 0; i < m; i++)
{
string a, b;
cin >> a >> b;
query[mp[a]].push_back(Query(mp[b], i));
query[mp[b]].push_back(Query(mp[a], i));
ansQue.push_back(make_pair(mp[a], mp[b]));
}
int rt;
for (int i = 1; i <= n; i++)
{
if (!inDegree[i])
{
rt = i;
break;
}
}
lca(rt, 0);
for (int i = 0; i < m; i++)
{
int fr = ansQue[i].first;
int to = ansQue[i].second;
if (fr == to)
{
printf("0\n");
}
else if (fr == ans[i])
{
printf("1\n");
}
else if (to == ans[i])
{
printf("%d\n", step[fr] - step[to]);
}
else
{
printf("%d\n", step[fr] - step[ans[i]] + 1);
}
}
}
return 0;
}
wa tarjan离线:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
map<string, int> mp;
vector<int> ans;
vector<pair<int, int> > ansQue;
int step[maxn];
int n;
vector<int> edge[maxn], query[maxn];
int inDegree[maxn];
int ancestor[maxn];
bool vis[maxn];
int fa[maxn];
int Rank[maxn];
void Init(int n)
{
mp.clear();
ans.clear();
ansQue.clear();
for (int i = 1; i <= n; i++)
{
fa[i] = i;
Rank[i] = 0;
edge[i].clear();
query[i].clear();
}
memset(vis, false, sizeof(vis));
memset(inDegree, 0, sizeof(inDegree));
memset(ancestor, 0, sizeof(ancestor));
memset(step, 0, sizeof(step));
}
int Find(int x)
{
if (fa[x] != x)
fa[x] = Find(fa[x]);
return fa[x];
}
void Union(int u, int v)
{
int fau = Find(u);
int fav = Find(v);
if (fau == fav)
return;
if (Rank[fau] < Rank[fav])
{
fa[fau] = fav;
}
else
{
fa[fav] = fau;
if (Rank[fau] == Rank[fav])
Rank[fau]++;
}
}
void lca(int rt, int num)
{
//自成集合
step[rt] = num;
ancestor[rt] = rt;
int sz = edge[rt].size();
for (int i = 0; i < sz; i++)
{
int v = edge[rt][i];
lca(v, num + 1); //递归子树
Union(rt, v); //合并子树与根
ancestor[Find(v)] = rt; //子树祖先也指向根
}
vis[rt] = true;
sz = query[rt].size();
for (int i = 0; i < sz; i++)
{
if (vis[query[rt][i]])
{
int v = query[rt][i];
ans.push_back(ancestor[Find(v)]);
}
}
return;
}
void bfs(int rt)
{
memset(step, -1, sizeof(step));
step[rt] = 1;
queue<int> q;
q.push(rt);
while (!q.empty())
{
int now = q.front();
q.pop();
int sz = edge[now].size();
for (int i = 0; i < sz; i++)
{
int v = edge[now][i];
if (step[v] == -1)
{
step[v] = step[now] + 1;
q.push(v);
}
}
}
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
int n, m;
scanf("%d%d", &n, &m);
Init(n);
int tot = 1;
for (int i = 1; i < n; i++)
{
string a, b;
cin >> a >> b;
if (mp.find(a) == mp.end())
{
mp[a] = tot++;
}
if (mp.find(b) == mp.end())
{
mp[b] = tot++;
}
edge[mp[b]].push_back(mp[a]);
inDegree[mp[a]]++;
}
for (int i = 0; i < m; i++)
{
string a, b;
cin >> a >> b;
query[mp[a]].push_back(mp[b]);
query[mp[b]].push_back(mp[a]);
ansQue.push_back(make_pair(mp[a], mp[b]));
}
// if (n == 1)
// {
// for (int i = 0; i < m; i++)
// {
// printf("0\n");
// }
// continue;
// }
int rt;
for (int i = 1; i <= n; i++)
{
if (!inDegree[i])
{
rt = i;
break;
}
}
// bfs(rt);
lca(rt, 0);
for (int i = 0; i < m; i++)
{
int fr = ansQue[i].first;
int to = ansQue[i].second;
if (fr == to)
{
printf("0\n");
}
else if (fr == ans[i])
{
printf("1\n");
}
else if (to == ans[i])
{
printf("%d\n", step[fr] - step[to]);
}
else
{
printf("%d\n", step[fr] - step[ans[i]] + 1);
}
}
}
return 0;
}
wa st在线:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <climits>
#include <cassert>
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);
map<string, int> mp;
int ind[maxn];
int head[maxn];
int edgeNum;
struct Edge
{
int fr, to, next;
int val;
} e[maxn << 1];
void initEdge()
{
memset(head, -1, sizeof(head));
edgeNum = 0;
}
void addEdge(int fr, int to, int val)
{
e[edgeNum].fr = fr;
e[edgeNum].to = to;
e[edgeNum].val = val;
e[edgeNum].next = head[fr];
head[fr] = edgeNum++;
e[edgeNum].fr = to;
e[edgeNum].to = fr;
e[edgeNum].val = val;
e[edgeNum].next = head[to];
head[to] = edgeNum++;
}
bool vis[maxn];
int dis[maxn]; //根节点到当前点的距离
int ver[maxn << 1]; //dfs遍历时节点的编号
int dep[maxn << 1]; //dfs遍历时节点的深度
int R[maxn]; //dfs遍历时第一次出现当前节点时的遍历序号
int tot; //下标计数器
void dfs(int u, int d)
{
vis[u] = true;
ver[++tot] = u;
R[u] = tot;
dep[tot] = d;
for (int i = head[u]; i != -1; i = e[i].next)
{
if (!vis[e[i].to])
{
int v = e[i].to;
int val = e[i].val;
dis[v] = dis[u] + val;
dfs(v, d + 1);
ver[++tot] = u;
dep[tot] = d;
}
}
}
//ST算法中保存的是当前段深度最小的节点的序号
int minDepVerIndex[maxn << 1][10];
// n = (n * 2 - 1)
void queryInit(int n)
{
for (int i = 1; i <= n; i++)
{
minDepVerIndex[i][0] = i;
}
for (int j = 1; (1 << j) <= n; j++)
{
for (int i = 1; i + (1 << j) - 1 <= n; i++)
{
int p = (1 << (j - 1));
int u = minDepVerIndex[i][j - 1];
int v = minDepVerIndex[i + p][j - 1];
minDepVerIndex[i][j] = dep[u] < dep[v] ? u : v;
}
}
}
int queryMin(int l, int r)
{
int k = log2((double)(r - l + 1));
int u = minDepVerIndex[l][k];
int v = minDepVerIndex[r - (1 << k) + 1][k];
return dep[u] < dep[v] ? u : v;
}
int lca(int u, int v)
{
int l = R[u];
int r = R[v];
if (l > r)
swap(l, r);
int index = queryMin(l, r);
return ver[index];
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase;
scanf("%d", &ncase);
while (ncase--)
{
int n, m;
scanf("%d%d", &n, &m);
tot = 1;
initEdge();
mp.clear();
memset(ind, 0, sizeof(ind));
for (int i = 1; i < n; i++)
{
string a, b;
cin >> a >> b;
if (mp.find(a) == mp.end())
{
mp[a] = tot++;
}
if (mp.find(b) == mp.end())
{
mp[b] = tot++;
}
addEdge(mp[a], mp[b], 1);
ind[mp[a]]++;
}
int rt;
for (int i = 1; i <= n; i++)
{
if (!ind[i])
{
rt = i;
break;
}
}
memset(vis, false, sizeof(vis));
tot = 0;
dis[1] = 0;
dfs(rt, 1);
queryInit((n << 1) - 1);
for (int i = 0; i < m; i++)
{
string a, b;
cin >> a >> b;
int fr = mp[a];
int to = mp[b];
int rt = lca(mp[a], mp[b]);
// cout << rt << endl;
if (fr == to)
puts("0");
else if (fr == rt)
puts("1");
else if (to == rt)
printf("%d\n", dis[fr] - dis[rt]);
else
printf("%d\n", dis[fr] - dis[rt] + 1);
}
}
return 0;
}