Approach
Subtree에 대한 정보를 가지고 이야기를 하고 있으므로, 오일러 투어 테크닉(ETT)를 활용하면 서브트리에 대한 정보를 쿼리 정보로 바꿔서 처리할 수 있다.
또한 추가적으로 쿼리에 대한 특정 수보다 작거나 크고 k번째 수의 경우는 머지 소트 트리를 활용해서 쉽게 풀 수 있다.
즉, 오일러 투어 테크닉(ETT)와 Mergesort Tree를 활용하면 쉽게 풀 수 있다.
느낌 자체는 https://viyoung.tistory.com/245
[백준 14287번] [세그먼트 트리 / 오일러 투어 테크닉] 회사 문화 3
Approach 가장 원초적으로 생각할 수 있는 풀이는 dfs로 계속 타고 내려가면서 계속 업데이트를 해주면 된다. 다만, 이 경우에는 시간복잡도가 $O(NM)$으로 시간이 초과하게 된다. 이때 등장하는 방법
viyoung.tistory.com
와 https://viyoung.tistory.com/258?category=884242 의 짬뽕이다.
[백준 13537번] [세그먼트 트리 / 머지소트 트리 / 스위핑] 수열과 쿼리1
Approach 특정 구간에서 k보다 작은 개수/큰 개수는 일반적으로 머지 소트 트리를 활용해서 처리하는 경우가 많다. 머지소트가 진행되는 양상을 잘 살펴보면, 세그먼트가 구성되는 느낌이랑 거의
viyoung.tistory.com
Code
#include <bits/stdc++.h>
#define fastio ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
vector<int> edge[200001];
int visited[200001];
int dfs_in[200001];
int dfs_out[200001];
vector<int> seg[800004];
int EulerTour(int node, int count){
visited[node] = 1;
dfs_in[node] = count;
for(int i = 0; i < edge[node].size(); i++){
int check = edge[node][i];
if(visited[check] == 0) count = EulerTour(edge[node][i], ++count);
}
dfs_out[node] = count;
return count;
}
void update(int node_index, int node_left, int node_right, int index, int value){
if(index < node_left || node_right < index) return;
seg[node_index].push_back(value);
if(node_left == node_right) return;
int mid = (node_left + node_right) / 2;
update(node_index * 2, node_left, mid, index, value);
update(node_index * 2 + 1, mid + 1, node_right, index, value);
}
int query(int node_index, int node_left, int node_right, int value, int cmp){
int query_left = dfs_in[value];
int query_right = dfs_out[value];
if(query_right < node_left || node_right < query_left) return 0;
if(query_left <= node_left && node_right <= query_right){
int up_c_count = seg[node_index].end() - upper_bound(seg[node_index].begin(), seg[node_index].end(), cmp);
return seg[node_index].size() - up_c_count;
}
int mid = (node_left + node_right) / 2;
return query(node_index * 2, node_left, mid, value, cmp) +
query(node_index * 2 + 1, mid + 1, node_right, value, cmp);
}
int main(void){
fastio;
memset(visited, 0, sizeof(visited));
memset(dfs_in, 0, sizeof(dfs_in));
memset(dfs_out, 0, sizeof(dfs_out));
int n, m, c;
cin >> n >> m >> c;
vector<int> data(n + 1);
for(int i = 1; i <= n; i++){
cin >> data[i];
}
for(int i = 0; i < n - 1; i++){
int a, b;
cin >> a >> b;
edge[a].push_back(b);
edge[b].push_back(a);
}
EulerTour(1, 1);
for(int i = 1; i <= n; i++){
update(1, 1, n, dfs_in[i], data[i]);
}
for(int i = 1; i < 800004; i++){
sort(seg[i].begin(), seg[i].end());
}
int result = 0;
for(int i = 0; i < m; i++){
int v, c;
cin >> v >> c;
result += (query(1, 1, n, v, c));
result %= 1000000007;
}
cout << result << "\n";
return 0;
}