일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 에라토스테네스의 체
- 정렬
- 누적합
- 투포인터
- 이분탐색
- 펜윅트리
- 플로이드와샬
- 삼분탐색
- 구현
- 백준
- 다익스트라
- 좌표압축
- 크루스칼
- 세그먼트트리
- 이분매칭
- 수학
- lis
- LazyPropagation
- BFS
- 위상정렬
- 이진탐색
- DP
- 브루트포스
- DisjointSet
- 그리디
- dfs
- lca
- 비트마스크
- boj
- MST
Archives
- Today
- Total
lastknight00
[백준]LCA와 쿼리(15480) 본문
문제 링크 : [백준]LCA와 쿼리(15480)
문제 설명
N개의 노드로 이루어진 트리가 주어집니다.
M개의 쿼리가 주어지는데, 루트 정보와 두 노드가 주어지면, 주어진 루트를 기준으로 두 노드의 LCA를 출력합니다.
입력
N(노드 갯수, 1 <= N <= 100,000)
Ai Bi(간선 정보
M(쿼리의 갯수, 1 <= M <= 100,000)
Ri Ui Vi(쿼리 정보)
7
1 2
2 3
2 4
1 5
5 6
4 7
5
1 2 7
3 1 5
2 1 7
5 6 2
6 2 3
출력
2
1
2
5
2
카테고리
#LCA
시간 복잡도 상한
O(MlogN)
해결 방법
- 일단 LCA정보는 필요 할 것 같으니까 만들어둡니다.
- 처음에는 루트가 두 노드의 경로에 있는 경우, 두 노드가 일직선에 있고, 루트가 그 밑에 있는 경우 등등 해서 만들어 보았으나, 쪼끔 맞고 틀립니다.
- 좀 더 공통적인 규칙을 찾아서 만들어 보도록 합니다.
- 주어진 노드가 세개이고, 각각의 LCA를 만드는 경우도 세가지가 있습니다.
- X : 루트와 A노드의 LCA
- Y : 루트와 B노드의 LCA
- Z : A, B 노드의 LCA
- 세 노드간의 관계는 또 세가지가 있습니다.
- A, B 모두 루트의 자식인 경우, Z가 답이 됩니다.
- Z는 깊이가 낮아도 루트의 깊이보다 낮지 않습니다.
- X, Y는 루트 노드가 됩니다.
- A, B 중 하나만 자식인 경우, 루트가 답이 됩니다.
- A, B 노드 중 루트의 자식의 LCA는 루트 노드가 되며, 그렇지 않은 노드는 루트보다 부모 노드가 됩니다.
- Z는 1에서 루트의 자식이 아닌 노드와의 LCA 노드가 됩니다.
- A, B 둘 다 루트의 자식이 아닌 경우, 루트와 두 노드의 LCA 중 루트에 가까운 노드가 답이 됩니다.(깊이가 깊은 노드)
- Z는 적어도 X, Y 중 깊이가 깊은 노드보다 깊이가 깊지 않습니다.
- A, B 모두 루트의 자식인 경우, Z가 답이 됩니다.
- 위 경우들을 종합해 볼 때, X, Y, Z 중 깊이가 가장 깊은 노드를 구하면 됩니다.
시간복잡도
O(MlogN)
코드
#include<iostream>
#include<vector>
#define N 100001
using namespace std;
int n,m,a,b,c,d[N],L[N][18],i,x,y,z;
vector<int>v[N];
void r(int p,int f){
d[p]=d[f]+1;
L[p][0]=f;
for(int i=1;i<18;i++)L[p][i]=L[L[p][i-1]][i-1];
for(int x:v[p])if(x!=f)r(x,p);
}
int l(int a,int b){
if(d[a]>d[b])swap(a,b);
for(i=17;i>=0;i--)if(d[b]-d[a]>=(1<<i))b=L[b][i];
if(a==b)return a;
for(i=17;i>=0;i--)if(L[b][i]!=L[a][i])a=L[a][i],b=L[b][i];
return L[a][0];
}
int main(){
ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(i=1;i<n;i++)cin>>a>>b,v[a].push_back(b),v[b].push_back(a);
r(1,0);
cin>>m;
while(m--){
cin>>a>>b>>c;
x=l(a,b);y=l(b,c);z=l(a,c);
a=d[x]>d[y]?x:y;
a=d[a]>d[z]?a:z;
cout<<a<<"\n";
}
}
'PS' 카테고리의 다른 글
[백준]대홍수(20314) (0) | 2020.11.29 |
---|---|
[백준]도로포장(1162) (0) | 2020.11.01 |
[백준]숨바꼭질 5(17071) (0) | 2020.10.31 |
[백준]철로(13334) (0) | 2020.10.31 |
[백준]오등큰수(17299) (0) | 2020.10.30 |
Comments