1. 程式人生 > >【模板】LCA Tarjan演算法 (模板題:洛谷P3379)

【模板】LCA Tarjan演算法 (模板題:洛谷P3379)

題目描述

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

輸入輸出格式

輸入格式:

第一行包含三個正整數N、M、S,分別表示樹的結點個數、詢問的個數和樹根結點的序號。

接下來N-1行每行包含兩個正整數x、y,表示x結點和y結點之間有一條直接連線的邊(資料保證可以構成樹)。

接下來M行每行包含兩個正整數a、b,表示詢問a結點和b結點的最近公共祖先。

輸出格式:

輸出包含M行,每行包含一個正整數,依次為每一個詢問的結果。

輸入輸出樣例

輸入樣例#1:
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
輸出樣例#1:
4
4
1
4
4

說明

時空限制:1000ms,128M

資料規模:對於100%的資料:N<=500000,M<=500000

樣例說明:

該樹結構如下:

第一次詢問:2、4的最近公共祖先,故為4。

第二次詢問:3、2的最近公共祖先,故為4。

第三次詢問:3、5的最近公共祖先,故為1。

第四次詢問:1、2的最近公共祖先,故為4。

第五次詢問:4、5的最近公共祖先,故為4。

故輸出依次為4、4、1、4、4。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX=500010;

struct bian{int tou,pre;}e[MAX*2];

struct question{
	int tou,pre,same,num;
	bool flag;
	question(){flag=false;}
}q[MAX*2];

int n,m,cnt_e=0,cnt_q=0,root;
int las[MAX],que[MAX],fa[MAX],res[MAX];
bool used[MAX];


inline int read()
{
    int out=0;char cc=getchar();
    while (cc>57||cc<48)cc=getchar();
    while (cc>=48&&cc<=57)
        out=out*10+cc-48,cc=getchar();
    return out;
}


void add_e(int x,int y){
	e[++cnt_e].tou=y;e[cnt_e].pre=las[x];las[x]=cnt_e;
	e[++cnt_e].tou=x;e[cnt_e].pre=las[y];las[y]=cnt_e;
}


void add_q(int x,int y,int k){
	q[++cnt_q].tou=y;q[cnt_q].same=cnt_q+1;
	q[cnt_q].pre=que[x];q[cnt_q].num =k;que[x]=cnt_q;
	q[++cnt_q].tou =x;q[cnt_q].same =cnt_q-1;
	q[cnt_q].pre =que[y];q[cnt_q].num =k;que[y]=cnt_q;
}


inline int sf(int d){
	if (fa[d]==d) return d;
	fa[d]=sf(fa[d]);return fa[d];
}
inline void marge(int x,int y){
	int f1=sf(x),f2=sf(y);
	fa[f2]=f1;
}


inline void Tarjan(int u,int father){
	for (int i=las[u];i!=0;i=e[i].pre )
	if (e[i].tou!=father && !used[e[i].tou]){
		Tarjan(e[i].tou,u);
		marge(u,e[i].tou);
		used[e[i].tou]=true;
	}
	for (int i=que[u];i!=0;i=q[i].pre)
	if (!q[i].flag && used[q[i].tou]){
		res[q[i].num]=sf(q[i].tou);
		q[i].flag=true;
		q[q[i].same].flag=true;
	}
}


int main(){
	int a,b;
	cin >>n>>m>>root;

	for (int i=1;i<=n-1;++i){fa[i]=i;a=read();b=read();add_e(a,b);}
	fa[n]=n;
	
	for (int i=1;i<=m;++i){a=read();b=read();add_q(a,b,i);}
	
	Tarjan(root,0);
	
	for(int i=1;i<=m;++i) printf("%d\n",res[i]);

	return 0;
}


相關推薦

模板LCA Tarjan演算法 模板P3379

題目描述 如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。 輸入輸出格式 輸入格式: 第一行包含三個正整數N、M、S,分別表示樹的結點個數、詢問的個數和樹根結點的序號。 接下來N-1行每行包含兩個正整數x、y,表示x結點和y結點之間有一條直接連線的邊

模板匈牙利演算法 二分圖匹配 模版P3386

題目背景 二分圖 題目描述 給定一個二分圖,結點個數分別為n,m,邊數為e,求二分圖最大匹配數 輸入輸出格式 輸入格式: 第一行,n,m,e 第二至e+1行,每行兩個正整數u,v,表示u

模板最小費用最大流增廣路模板P3381

題目描述 如題,給出一個網路圖,以及其源點和匯點,每條邊已知其最大流量和單位流量費用,求出其網路最大流和在最大流情況下的最小費用。 輸入輸出格式 輸入格式: 第一行包含四個正整數N、M、S、T,分別表示點的個數、有向邊的個數、源點序號、匯點序號。 接下來M行每行包

模板三分法 模板P3382

題目描述 如題,給出一個N次函式,保證在範圍[l,r]記憶體在一點x,使得[l,x]上單調增,[x,r]上單調減。試求出x的值。 輸入輸出格式 輸入格式: 第一行一次包含一個正整數N和兩個實數l、r,含義如題目描述所示。 第二行包含N+1個實數,從高到低依次表示該

luogu P4718 模板Pollard-Rho演算法貼程式碼

嘟嘟嘟 從標題中能看出來,我只是想貼一個程式碼。 先扯一會兒。 前幾天模擬考到了這東西,今天有空就學了一下。 到網上找資料,發現前置技能是miller-rabin篩法,於是我還得先學這麼個東西。 學miller-rabin的話不得不推薦這兩篇文章: 大數質因解:淺談Miller-Rabin和Pollard

P3919 模板可持久化陣列可持久化線段樹/平衡樹-可持久化線段樹(單點更新,單點查詢)

P3919 【模板】可持久化陣列(可持久化線段樹/平衡樹) 題目背景 UPDATE : 最後一個點時間空間已經放大 標題即題意 有了可持久化陣列,便可以實現很多衍生的可持久化功能(例如:可持久化並查集) 題目描述 如題,你需要維護這樣的一個長度為 NN 的陣列,支援如下幾種操作

P3919 模板可持久化陣列可持久化線段樹/平衡樹

主席樹太費空間了,而本題也無需維護任何區間資訊,只是查詢歷史版本點值,沒必要構造可持久化線段樹,我們可以構建結構類似於 BST 的可持久化資料結構,這樣每個非葉節點也會帶有權值,不會被浪費掉 Code; #include<cstdio> #include<algorit

Luogu P3919 模板可持久化陣列可持久化線段樹/平衡樹

題面跳轉站 題目背景 UPDATE : 最後一個點時間空間已經放大 標題即題意 有了可持久化陣列,便可以實現很多衍生的可持久化功能(例如:可持久化並查集) 題目描述 如題,你需要維護這樣的一個長度為 NN 的陣列,支援如下幾種操作 在某個歷史版

P3919 模板可持久化陣列可持久化線段樹/平衡樹

主席樹模板題,學了下主席樹的模板 主席樹的核心思想是每次儲存下來每次單點修改之後的線段樹的資料,但這樣肯定會mle,所以有一個優化的方法:因為每次只更新一個點,那麼在這個線段樹裡只有這個點所在的那一條鏈可能會修改,也就是說我們只要記錄這一條鏈就足夠了,其他的資料我們只要

模板帶修改莫隊 模板P1903數顏色

帶修改莫隊講解 ~閱前提示: 擁有普通莫隊的基礎知識;理解莫隊的思想; ~簡介: 莫隊支援的是離線操作,普通莫隊只支援查詢操作; 而帶修改莫隊還支援單點修改操作。 ~原理: 普通莫隊每一個詢問有L,R,ID三個屬性;因為只有查詢操作,所以改變其查詢順序並不會影響演算法

字串匹配演算法位運算的魔法——KR與SO

位運算經常能做出一些不可思議的事情來,例如不用臨時變數要交換兩個數該怎麼做呢?一個沒接觸過這類問題的人打死他也想不出來。如果拿圍棋來做比喻,那麼位運算可以喻為程式設計中的“手筋”。 按位的儲存方式能提供最大的儲存空間利用率,而隨著空間被壓縮的同時,由於CPU硬體的直接支援,速度竟然神奇般

BZOJ3667Rabin-Miller演算法Pollard_pho演算法

Input 第一行:CAS,代表資料組數(不大於350),以下CAS行,每行一個數字,保證在64位長整形範圍內,並且沒有負數。你需要對於每個數字:第一,檢驗是否是質數,是質數就輸出Prime 第二,如果不是質數,輸出它最大的質因子是哪個。 Output

作業系統頁面置換演算法最佳置換演算法C語言實現

# 【作業系統】頁面置換演算法(最佳置換演算法)(C語言實現) #####(編碼水平較菜,寫部落格也只是為了個人知識的總結和督促自己學習,如果有錯誤,希望可以指出) ## 1.頁面置換演算法: > 在地址對映過程中,若在頁面中發現所要訪問的頁面不在記憶體中,則產生缺頁中斷。當發生缺頁中斷時,如果作業系

BZOJ4869相逢是問候線段樹,歐拉定理

post class problem spa bzoj struct printf 計算 oid 【BZOJ4869】相逢是問候(線段樹,歐拉定理) 題面 BZOJ 題解 根據歐拉定理遞歸計算(類似上帝與集合的正確用法) 所以我們可以用線段樹維護區間最少的被更新的多少次 如

BZOJ3309DZY Loves Math莫比烏斯反演

namespace ... ++ bre getchar stream 那種 getc 分解質 【BZOJ3309】DZY Loves Math(莫比烏斯反演) 題面 求 \[\sum_{i=1}^a\sum_{j=1}^bf(gcd(a,b))\] 其中,\(f(x)\)

bzoj3083遙遠的國度樹鏈剖分+線段樹

region ont lin names 一個點 輸入輸出格式 -- wap 操作數 題目描述 zcwwzdjn在追殺十分sb的zhx,而zhx逃入了一個遙遠的國度。當zcwwzdjn準備進入遙遠的國度繼續追殺時,守護神RapiD阻攔了zcwwzdjn的去路,他需要zcw

BZOJ3551Peaks加強版Kruskal重構樹,主席樹

www top return ostream https zoj 高度 ble lib 【BZOJ3551】Peaks加強版(Kruskal重構樹,主席樹) 題面 BZOJ Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之

BZOJ1078[SCOI2008]斜堆性質

max turn str return name als oid 題目 getc 【BZOJ1078】[SCOI2008]斜堆(性質題) 題面 BZOJ 洛谷 題解 考慮一下這道題目的性質吧。思考一下最後插入進來的數是什麽樣子的。首先因為它是最後插入進來的,所以一定是比某個

BZOJ1898[ZJOI2005]沼澤鱷魚矩陣快速冪,動態規劃

表示 ear 構建 esp ++ 方案 set 沒有 ring 【BZOJ1898】[ZJOI2005]沼澤鱷魚(矩陣快速冪,動態規劃) 題面 BZOJ 洛谷 題解 先吐槽,說好了的鱷魚呢,題面裏面全是食人魚 看到數據範圍一眼想到矩乘。 先不考慮食人魚的問題,直接設\(f[

UVA10816Travel in Desert 最小瓶頸路+最短路

UVA10816 Travel in Desert 題目大意 沙漠中有一些道路,每個道路有一個溫度和距離,要求s,t兩點間的一條路徑,滿足溫度最大值最小,並且長度最短 輸入格式 輸入包含多組資料。 每組資料第一行為兩個整數\(n\) 和\(e\) 。表示綠洲數量和連線綠洲的道路數量。 每組資料第二