LCA tarjan+并查集POJ1470

LCA tarjan+并查集POJ1470

https://www.cnblogs.com/JVxie/p/4854719.html

不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻

这是个离线算法,现在的粗略理解是输入完毕询问完毕后进行解决的算法

用了并查集

1···选取根节点

2···逐个dfs访问所选节点所有的子节点v

  3···1··对于子节点的dfs访问到头之后

  3···2··标记,进行询问查询

  3···3··如果查询的点访问过,输出其目前祖先

  4···回溯,合并边,更新pre数组(并查集)

5.所有节点访问完毕,结束

1.任选一个点为根节点,从根节点开始。

2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。

3.若是v还有子节点,返回2,否则下一步。

4.合并v到u上。

5.寻找与当前点u有询问关系的点v。

6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点

模拟别人打了一下代码

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 1000;
const int maxm = 1000;

struct node{
    int to,pre;
}e[maxn * maxn],q[maxn * maxn];
int pre[maxn];
bool vis[maxn];
int id[maxn],cnt;
int idq[maxn],cntq;
int in[maxn];
int ans[maxn];
int root;
void init(int n)
{
    memset(id,-1,sizeof(id));
    memset(idq,-1,sizeof(idq));
    cntq = 0;
    cnt = 0;
    memset(in,0,sizeof(in));
    memset(ans,0,sizeof(ans));
    memset(vis,0,sizeof(vis));
    for(int i = 0;i <= n;i++)
        pre[i] = i;
}
void add(int from,int to)
{
    e[cnt].to = to;
    e[cnt].pre = id[from];
    id[from] = cnt++;
}
void addq(int from,int to)
{
    q[cntq].to = to;
    q[cntq].pre = idq[from];
    idq[from] = cntq++;
}
int Find(int x)
{
    if(pre[x] == x)return x;
    return pre[x] = Find(pre[x]);
}
void join(int u,int v)
{
    int fu = Find(u);
    int fv = Find(v);
    pre[fv] = fu;
}
void LCA(int rt)
{
    for(int i = id[rt];~i;i = e[i].pre)
    {
        int to = e[i].to;
        LCA(to);
        join(rt,to);
    }
    vis[rt] = 1;
    for(int i = idq[rt];~i;i = q[i].pre)
    {
        int que = q[i].to;
        if(vis[que])
            ans[Find(que)]++;
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        init(n);
        int x,y,z;
        for(int i = 0;i < n;i++)
        {
            scanf("%d:(%d)",&x,&y);
            for(int j = 0;j < y;j++)
            {
                scanf("%d",&z);
                in[z] = 1;
                add(x,z);
            }
        }
        int t;
        scanf("%d",&t);
        while(t--)
        {
            while(getchar() !='(');
            scanf("%d%d",&x,&y);
            addq(x,y);
            addq(y,x);
        }
        while(getchar() != ')');
        for(int i = 1;i <= n;i++)
            if(!in[i])root = i;
        LCA(root);
        for(int i = 1;i <= n;i++)
        {
            if(ans[i] != 0)
                printf("%d:%d\n",i,ans[i]);
        }
    }
    return 0;
}

 现在我要自己去大一下模板提啦

http://node2.vjmirror.rainng.com/contest/241642#problem/A

题意也是模板题意,很简单,错了两个地方都是小失误。。。。

一个是两个for循环索引都是i

另一个是空间没开够

略略略

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn = 1100;
int id[maxn],cnt;
int qid[maxn],qcnt;
struct node
{
    int to,pre;
}e[maxn];
struct node2
{
    int to,ID,pre;
}q[maxn * 3];
int pre[maxn];
bool vis[maxn];
int ans[maxn];
void init(int n)
{
    memset(id,-1,sizeof(id));
    memset(qid,-1,sizeof(qid));
    memset(vis,0,sizeof(vis));
    cnt = qcnt = 0;
    for(int i = 0;i <= n;i++)
        pre[i] = i;
}
void add(int from,int to)
{
    e[cnt].to = to;
    e[cnt].pre = id[from];
    id[from] = cnt++;
}
void qadd(int from,int to,int I)
{
    q[qcnt].to = to;
    q[qcnt].pre = qid[from];
    q[qcnt].ID = I;
    qid[from] = qcnt++;
}
int Find(int x)
{
    if(x == pre[x])return x;
    return pre[x] = Find(pre[x]);
}
void join(int u,int v)
{
    int fu = Find(u),fv = Find(v);
    if(fu != fv)
        pre[fv] = fu;
}
void tarjan(int rt)
{

    //cout<<"cs"<<" "<<rt<<endl;
    for(int i = id[rt];~i;i = e[i].pre)
    {
        int to = e[i].to;
        tarjan(to);
        join(rt,to);
    }
    vis[rt] = 1;
    for(int i = qid[rt];~i;i = q[i].pre)
    {
        int que = q[i].to;
        if(vis[que])
        {
            ans[q[i].ID] = Find(que);
            //cout<<Find(que)<<endl;
        }
    }
}
int main()
{
    int t,n,m;
    scanf("%d",&t);
    int cas = 1;
    while(t--)
    {
        scanf("%d",&n);
        init(n);
        for(int i = 1;i <= n;i++)
        {
            int n_num,v;
            scanf("%d",&n_num);
            for(int j = 0;j < n_num;++j)
            {
                scanf("%d",&v);
                add(i,v);
            }
        }
        scanf("%d",&m);
        int u,v;
        for(int i = 1;i <= m;i++)
        {
            scanf("%d%d",&u,&v);
            qadd(u,v,i);
            qadd(v,u,i);
        }
        tarjan(1);
        printf("Case %d:\n",cas++);
        for(int i = 1;i <= m;i++)
        {
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/DF-yimeng/p/9427228.html