Pku 1470 Closest Common Ancestors

最近在学习LCA的Tarjan算法,用来做1330秒过了。但是做1470的时候遇到了不小的麻烦。

本题大意:给出一棵树,给出所有的LCA询问,输出所有点成为LCA点的次数(为0不输出);

分析:这道题和1330的不同之处在于

1.LCA多次询问,需要另外建立查询表统计

2.输入时候需要特殊处理

 

接着道题时贡献了无数的RE,原因不清楚,都是用邻接表建树写的,后来改成STl里的vector容器建树就AC了,第一次利用STl容器做题,虽然过了,但是还是没想明白从前屡试不爽的邻接表怎么就会出问题,两个代码我都列下,以后再慢慢看。

另外试了一下,不用anc数组记录公共祖先点,直接不更新并查集代表节点,用并查集代表元节点似乎更快一点,运行情况对比如下

3016K688MS 1668B

3020K750MS 1796B

vector的:

 

#include<stdio.h>
#include<memory.h>
#include<vector>
using namespace std;
#define N 1001
#define Clear(a) memset(a,0,sizeof(a))
vector<int> E[N],Q[N];
int n,m,root;
int father[N],count[N],color[N],anc[N],d[N];

void InitData()
{
    int u,v,i,j,k;
    Clear(d);
    Clear(count);
    Clear(color);
    for(i=1;i<=n;i++)
        Q[i].clear(),E[i].clear();
    for(k=1;k<=n;k++){
        scanf("%d",&u);
        while(getchar()!='(');
        scanf("%d",&i);
        while(getchar()!=')');
        for(j=1;j<=i;j++){
            scanf("%d",&v);
            d[v]++;
            E[u].push_back(v);
        }
    }
    for(root=1;root<=n;root++)
        if(!d[root])
            break;
    scanf("%d",&m);
    for(j=1;j<=m;j++){
        while(getchar()!='(');
        scanf("%d%d",&u,&v);
        if(u==v)
            count[u]++;
        else{
            Q[u].push_back(v);
            Q[v].push_back(u);
        }
        while(getchar()!=')');
    }
}
int find_set(int s)
{
    for(;s!=father[s];s=father[s]);
    return s;
}
void union_set(int u,int v)
{
    int up=find_set(u);
    int vp=find_set(v);
    if(up!=vp)
        father[vp]=up;
}
void dfs(int s)
{
    father[s]=s;
    anc[s]=s;
    for(int i=0;i<E[s].size();i++){
        dfs(E[s][i]);
        union_set(s,E[s][i]);
        anc[find_set(s)]=s;
    }
    color[s]=1;
    for(int i=0;i<Q[s].size();i++){
        if(color[Q[s][i]])
            count[anc[find_set(Q[s][i])]]++;
    }
}
void show()
{
    for(int i=1;i<=n;i++)
        if(count[i])
            printf("%d:%d/n",i,count[i]);
}
int main()
{  //  freopen("data.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        InitData();
        dfs(root);
        show();
    }
    return 0;
}
邻接表的:
#include<stdio.h>
#include<memory.h>
#define N 1001
#define Clear(a) memset(a,0,sizeof(a))
struct Edge
{
    int v;
    Edge *link;
    Edge(int v0,Edge *e):v(v0),link(e){}
}*E[N],*Q[N];
int n,m,root;
int father[N],count[N],color[N],anc[N],d[N];

void InitData()
{
    int u,v,i,j,k;
    Clear(E);
    Clear(Q);
    Clear(d);
    Clear(count);
    Clear(color);
    for(k=1;k<=n;k++){
        scanf("%d",&u);
        while(getchar()!='(');
        scanf("%d",&i);
        while(getchar()!=')');
        for(j=1;j<=i;j++){
            scanf("%d",&v);
            d[v]++;
            E[u]=new Edge(v,E[u]);
        }
    }
    for(root=1;root<=n;root++)
        if(!d[root])
            break;
    scanf("%d",&m);
    for(j=1;j<=m;j++){
        while(getchar()!='(');
        scanf("%d%d",&u,&v);
        if(u==v)
            count[u]++;
        else{
            Q[u]=new Edge(v,Q[u]);
            Q[v]=new Edge(u,Q[v]);
        }
        while(getchar()!='(');
    }
}
int find_set(int s)
{
    for(;s!=father[s];s=father[s]);
    return s;
}
void union_set(int u,int v)
{
    int up=find_set(u);
    int vp=find_set(v);
    if(up!=vp)
        father[vp]=up;
}
void dfs(int s)
{
    father[s]=s;
    anc[s]=s;
    for(Edge *e=E[s];e;e=e->link){
        dfs(e->v);
        union_set(s,e->v);
        anc[find_set(s)]=s;
    }
    color[s]=1;
    for(Edge *e=Q[s];e;e=e->link){
        if(color[e->v])
            count[anc[find_set(e->v)]]++;
    }
}
void show()
{
    for(int i=1;i<=n;i++)
        if(count[i])
            printf("%d:%d/n",i,count[i]);
}
int main()
{  //  freopen("data.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        InitData();
        dfs(root);
        show();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值