hdu 4547 lca-tarjan离线算法

题意:


Problem Description
  在Windows下我们可以通过cmd运行DOS的部分功能,其中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操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
 

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值