1. 程式人生 > >(題目總結)LCA板子以及一些題目

(題目總結)LCA板子以及一些題目

style 更新 not tro nec 技術分享 har read conn

---恢復內容開始---

LCA算法總結

把lca題目記入下來!分享給你們

板子tarjan(離線)

技術分享圖片
#define N 10005
#define M 1000005
// N 表示的樹的節點
// M 表示的問題數 
int cnt_e,cnt_q,head_e[N],head_q[N],vis[N],dis[N],t,ans[M],id[N],f[N];
// 邊,問題數 
struct node{
    int u,w,next;
}e[N*2],q[M*2];
void init(){
    memset(head_e,-1,sizeof(head_e));
    memset(head_q,
-1,sizeof(head_q)); memset(vis,0,sizeof(vis)); cnt_e=0; cnt_q=0; } void addedge(int x,int y,int z){ e[cnt_e].u=x;e[cnt_e].w=z;e[cnt_e].next=head_e[y];head_e[y]=cnt_e++; e[cnt_e].u=y;e[cnt_e].w=z;e[cnt_e].next=head_e[x];head_e[x]=cnt_e++; } void addquery(int x,int y,int z){ q[cnt_q].u
=x;q[cnt_q].w=z;q[cnt_q].next=head_q[y];head_q[y]=cnt_q++; q[cnt_q].u=y;q[cnt_q].w=z;q[cnt_q].next=head_q[x];head_q[x]=cnt_q++; } int find(int x){ if(f[x] == x) return x; else return f[x] = find(f[x]); } void tarjan(int k){ f[k]=k; vis[k]=1; id[k]=t;
int i,v; for(i=head_q[k];i!=-1;i=q[i].next){ v=q[i].u; if(vis[v]){ // 表示的就是一顆樹 // 每次只需要在這裏做文章就行 // ans[q[i].w] = find(v); //求的是lca //ans[q[i].w]=dis[k]+dis[v]-2*dis[find(v)]; //求的是兩個點的距離 // solve1() 可以表示的是森林 //可以去求這個森林 if(id[v] == id[k]) //ans[q[i].w] = find(v); ans[q[i].w] = dis[k]+dis[v]-2*dis[find(v)]; else ans[q[i].w]=-1; } } for(i=head_e[k];i!=-1;i=e[i].next){ v=e[i].u; if(!vis[v]){ dis[v]=dis[k]+e[i].w; tarjan(v); f[v]=k; } } }
View Code


LCA第一題:

給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先

題意:-------
我的理解:
直接套板子(因為是一顆樹!直接套solve2)
AC 代碼

技術分享圖片
#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<string>
#include<set>

typedef long long int ll;

using namespace std;

void read(int &x){
        int f=1;x=0;char s=getchar();
        while(s<0||s>9){if(s==-)f=-1;s=getchar();}
        while(s>=0&&s<=9){x=x*10+s-0;s=getchar();}
        x*=f;
}
#define N 500005
#define M 1000005
// N 表示的樹的節點
// M 表示的問題數 
int cnt_e,cnt_q,head_e[N],head_q[N],vis[N],dis[N],t,ans[M],id[N],f[N];
// 邊,問題數 
struct node{
    int u,w,next;
}e[N*2],q[M*2];
void init(){
    memset(head_e,-1,sizeof(head_e));
    memset(head_q,-1,sizeof(head_q));
    memset(vis,0,sizeof(vis));
    cnt_e=0;    
    cnt_q=0;
}
void addedge(int x,int y,int z){
    e[cnt_e].u=x;e[cnt_e].w=z;e[cnt_e].next=head_e[y];head_e[y]=cnt_e++;
    e[cnt_e].u=y;e[cnt_e].w=z;e[cnt_e].next=head_e[x];head_e[x]=cnt_e++;
}
void addquery(int x,int y,int z){
    q[cnt_q].u=x;q[cnt_q].w=z;q[cnt_q].next=head_q[y];head_q[y]=cnt_q++;
    q[cnt_q].u=y;q[cnt_q].w=z;q[cnt_q].next=head_q[x];head_q[x]=cnt_q++;
}
int find(int x){
    if(f[x] == x)
    return x;
    else
    return f[x] = find(f[x]);
}
void tarjan(int k){
    f[k]=k;
    vis[k]=1;
    id[k]=t;
    int i,v;
    for(i=head_q[k];i!=-1;i=q[i].next){
        v=q[i].u;
        if(vis[v]){
            
            // 表示的就是一顆樹 
            // 每次只需要在這裏做文章就行
            ans[q[i].w] = find(v);                      //求的是lca 
            //ans[q[i].w]=dis[k]+dis[v]-2*dis[find(v)];    //求的是兩個點的距離 
            
             
            //  solve1() 可以表示的是森林 
            //可以去求這個森林 
            /*
            
            //ans[q[i].w] = find(v);
            ans[q[i].w] = dis[k]+dis[v]-2*dis[find(v)];
            else
            ans[q[i].w]=-1;
            */
        }
    }
    for(i=head_e[k];i!=-1;i=e[i].next){
        v=e[i].u;
        if(!vis[v]){
            dis[v]=dis[k]+e[i].w;
            tarjan(v);
            f[v]=k;
        }
    }
}

void solve1(){
    int n, m, cc, root, x, y, z;
    while(scanf("%d%d%d",&n,&cc,&m) == 3){
        init();
        while(cc--){
            //scanf("%d%d%d",&x,&y,&z);
            read(x),read(y),read(z);
            //z = 1;
            addedge(x,y,z);
        }
        for(int i = 0;i < m; i++){
            read(x),read(y);
            //scanf("%d%d",&x,&y);
            addquery(x,y,i);
        }
        t = 0;    // 這個是全局的變量
        for(int i = 1; i <= n; i++, t++){
            if(!vis[i]){
                dis[i] = 0;
                tarjan(i);
            }
        } 
        for(int i = 0; i < m; i++){
            if(ans[i] == -1){                    //                表示的就是不在一顆樹 
                puts("Not connected");
            }else
                printf("%d\n",ans[i]);
        }
    } 
}
void solve2(){
    
    // 需要註意的就是這個tarjan 裏面ans換下就可以求一顆樹
    
    int tt ;
    
    //read(tt);
    tt = 1;
    while(tt--){
        int n, m, cc, root, x, y, z;
        read(n),read(m),read(root);
        init();
        for(int i = 1; i < n; i++){
            read(x),read(y);
            //read(z);
            z = 1;
            //scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z);
        } 
        for(int i = 0; i < m; i++){
            read(x),read(y);
            addquery(x,y,i);
        }
        // 一顆樹的話,一般root 為1 ///只有一顆樹,t 默認為0
        // root = 1;
        t = 0;  
        dis[root] = 0;
        tarjan(root);
        for(int i = 0; i < m; i++){
            printf("%d\n",ans[i]);
        } 
    }
}
int main(){
    
    int tt;
    //read(tt);
    tt = 1;
    while(tt--){
        // 1 表示的就是森林 
        //solve1();
        
        solve2();
    } 
    return 0;    
}
AC

持續更新中

(題目總結)LCA板子以及一些題目