1. 程式人生 > 實用技巧 >P4248 [AHOI2013]差異(字尾陣列+單調棧)

P4248 [AHOI2013]差異(字尾陣列+單調棧)

https://www.luogu.com.cn/problem/P3379

\(Tarjan\)\(LCA\)

\(dfs\)訪問每個節點,當一個節點被訪問結束後,直接將該節點並在它的父親上,然後處理詢問

\(vector\)儲存一端在\(u\)的詢問,倘若\(v\)已經被訪問到了,那麼把\(v\)所並的集合的祖先取出就是該詢問的答案。因為一個集合為一個子樹,\(v\)已經被訪問到了,那麼這個集合就是包含\(u,v\)的最小子樹根節點,當然是\(lca\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define N 500005
using namespace std;
int n,m,rt,x,y,tot,f[N],fr[N],nxt[N << 1],d[N << 1];
int rf[N],ans[N];
struct node
{
    int x,y;
    node (int xx=0,int yy=0)
    {
        x=xx,y=yy;
    }
};
vector<node>e[N];
void add(int x,int y)
{
    tot++;
    d[tot]=y;
    nxt[tot]=fr[x];
    fr[x]=tot;
}
int getf(int x)
{
    return (x==rf[x])?x:(rf[x]=getf(rf[x]));
}
void dfs(int u)
{
    rf[u]=u;
    for (int i=fr[u];i;i=nxt[i])
    {
        int v=d[i];
        if (v==f[u])
            continue;
        f[v]=u;
        dfs(v);
        rf[v]=u;
    }
    for (vector<node> :: iterator it=e[u].begin();it!=e[u].end();++it)
        if (rf[it->x])
            ans[it->y]=getf(it->x);
}
int main()
{
    scanf("%d%d%d",&n,&m,&rt);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    for (int i=1;i<=m;i++)
        scanf("%d%d",&x,&y),e[x].push_back(node(y,i)),e[y].push_back(node(x,i));
    dfs(rt);
    for (int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}