学习LCA( 最近公共祖先·二)

http://poj.org/problem?id=1986

离线找u,v之间的最小距离(理解推荐)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
char s[2];
const int M=1e5+5;
const int N=2e4+4;
struct node{
    int v,w,nextt;
}e[M];
struct NODE{
    int v,dis,nextt;
}g[M];
int fa[M],head[M],Head[M],vis[M],dis[M];
int tot,TOT;
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=w;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
///存储询问的u,v
void ADDedge(int u,int v){
    g[TOT].v=v;
    g[TOT].nextt=Head[u];
    Head[u]=TOT++;
    g[TOT].v=u;
    g[TOT].nextt=Head[v];
    Head[v]=TOT++;
}
int Find(int x){
    return fa[x]==x?x:fa[x]=Find(fa[x]);
}
void LCA(int u){
    fa[u]=u;
    vis[u]=true;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(!vis[v]){
            dis[v]=dis[u]+e[i].w;
            LCA(v);
            fa[v]=u;
        }
    }
    for(int i=Head[u];~i;i=g[i].nextt){
        int v=g[i].v;
        if(vis[v]){
            g[i].dis=dis[u]+dis[v]-2*dis[Find(v)];
            g[i^1].dis=g[i].dis;
        }
    }
}
int main(){
    int n,m;
    memset(head,-1,sizeof(head));
    memset(Head,-1,sizeof(Head));
    scanf("%d%d",&n,&m);
    while(m--){
        int u,v,w;
        scanf("%d%d%d%s",&u,&v,&w,s);
        addedge(u,v,w);
    }
    int k;
    scanf("%d",&k);
    for(int i=0;i<k;i++){
        int  u,v;
        scanf("%d%d",&u,&v);
        ADDedge(u,v);
    }
    LCA(1);
    for(int i=0;i<TOT;i+=2){
        printf("%d\n",g[i].dis);
    }
    return 0;
}
View Code

 

 

http://hihocoder.com/problemset/problem/1067

tangin+离线

#include<bits/stdc++.h>
using namespace std;
const int M=1e5+10;
struct node{
    int to,index;
    node (int v,int index){
        this->to=v;
        this->index=index;
    }
};
vector<int>graph[M];
vector<node>e[M];
bool sign[M];
map<int,string>str;
map<string,int>indx;
int ans[M];

int f[M],color[M];
int tot,n,m,root;
void init(){
    tot=0;
    indx.clear();
    memset(sign,false,sizeof(sign));
    memset(color,0,sizeof(color));
    memset(ans,0,sizeof(ans));
    for(int i=0;i<M;i++){
        graph[i].clear();
        e[i].clear();
        f[i]=i;
    }
}
int find(int x){
    return x==f[x]?x:f[x]=find(f[x]);
}
int get_index(string x){
    if(indx.count(x))
        return indx[x];
    indx[x]=++tot;
    str[tot]=x;
    return tot;
}
void input(){
    cin>>n;
    for(int i=1;i<=n;i++){
        string name1,name2;
        cin>>name1>>name2;
        int a=get_index(name1);
        int b=get_index(name2);
        graph[a].push_back(b);
        sign[b]=true;
    }
    cin>>m;
    for(int i=1;i<=m;i++){
        string name1,name2;
        cin>>name1>>name2;
        int a=get_index(name1);
        int b=get_index(name2);
        e[a].push_back(node(b,i));
        e[b].push_back(node(a,i));
    }
}
void targin(int u){
    color[u]=1;
    for(int i=0;i<e[u].size();i++){
        int ID=e[u][i].index;
        if(ans[ID])
            continue;
        int v=e[u][i].to;
        if(color[v]==0)
                //0代表v未访问过
            continue;
        if(color[v]==1)
                //1代表正在访问,所以u和v的最近公共祖先就是v
            ans[ID]=v;
        if(color[v]==2)
                //2代表访问完毕的点,所以u和v的最近公共祖先就是v当前的祖先
            ans[ID]=find(v);
    }
    for(int i=0;i<graph[u].size();i++){
        int v=graph[u][i];
        targin(v);
                //一个节点dfs完后,标记vv为访问完毕的点,并更新父节点
        color[v]=2;
        f[v]=u;
    }
}
void solve(){
    for(int i=1;i<=n;i++)
        if(!sign[i])
            root=i;
    targin(root);
    for(int i=1;i<=m;i++)
        cout<<str[ans[i]]<<endl;
}
int main(){
    init();
    input();
    solve();
    return 0;
}        

 

posted @ 2019-04-21 17:23  starve_to_death  阅读(123)  评论(0编辑  收藏  举报