E - Count Descendants
第一种做法: 对于每个节点来说,子节点一定在dfs序进出之间,先处理出深度,然后根据dfs序在深度中二分查找
// #pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
// #pragma GCC optimize(3 , "Ofast" , "inline")
// #pragma GCC optimize("Ofast")
// #pragma GCC target("avx,avx2,fma")
// #pragma GCC optimization("unroll-loops")
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#include <bitset>
#include <deque>
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0)
#define x first
#define y second
#define pb push_back
#define ls rt << 1
#define rs rt << 1 | 1
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
int n , m ;
vector<int> v[N] ;
vector<int> dep[N] ;
int in[N] , out[N] , idx = 0 ;
void dfs(int u , int d) {
in[u] = ++ idx ;
dep[d].pb(in[u]) ;
for(auto x : v[u])
dfs(x , d + 1) ;
out[u] = ++ idx ;
}
int work()
{
cin >> n ;
for(int i = 2; i <= n ;i ++ ) {
int x ;
cin >> x ;
v[x].pb(i) ;
}
cin >> m ;
dfs(1 , 0) ;
while(m -- ) {
int x , y ;
cin >> x >> y ;
cout << (int)(upper_bound(dep[y].begin() , dep[y].end() , out[x]) - lower_bound(dep[y].begin() , dep[y].end() , in[x]))<< "\n";
}
return 0 ;
}
int main()
{
// freopen("C://Users//spnooyseed//Desktop//in.txt" , "r" , stdin) ;
// freopen("C://Users//spnooyseed//Desktop//out.txt" , "w" , stdout) ;
work() ;
return 0 ;
}
/*
*/
第二种做法:用树上启发式合并暴力求解,先预存一下每个点对应哪些操作,然后在统计答案的时候,直接维护一个当前节点子树中某个深度的个数,cnt[dep[u]] 。
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3 , "Ofast" , "inline")
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#include <bitset>
#include <deque>
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0)
#define x first
#define y second
#define pb push_back
#define ls rt << 1
#define rs rt << 1 | 1
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
vector<int> v[N] ;
int n , dep[N] ,son[N] , sz[N] ;
vector<PII> q[N] ;
int cnt[N] ;
int vis[N] , ans[N] ;
void dfs(int u , int f) {
dep[u] = dep[f] + 1 ;
sz[u] = 1 ;
for(auto x : v[u]) {
if(x == f) continue ;
dfs(x , u) ;
sz[u] += sz[x] ;
if(sz[x] > sz[son[u]]) son[u] = x ;
}
}
void upd(int u , int f , int k) {
cnt[dep[u]] += k ;
for(auto x : v[u]) {
if(x == f || vis[x]) continue ;
upd(x , u , k) ;
}
}
void dsu(int u , int f , int keep) {
for(auto x : v[u]) {
if(x == f || x == son[u]) continue ;
dsu(x , u , 0) ;
}
if(son[u]) dsu(son[u] , u , 1) , vis[son[u]] = 1 ;
upd(u , f , 1) ;
for(auto x : q[u])
if(x.x >= dep[u]) ans[x.y] = cnt[x.x] ;
if(son[u]) vis[son[u]] = 0 ;
if(!keep) upd(u , f , -1) ;
}
int work()
{
scanf("%d" , &n) ;
for(int i = 2 , x ;i <= n ;i ++ ) scanf("%d" , &x) , v[x].pb(i) ;
int m ;
scanf("%d" , &m) ;
for(int i = 1; i <= m ;i ++ ) {
int x , d ;
scanf("%d%d" , &x , &d) ;
q[x].pb({d + 1 , i}) ;
}
dfs(1 , 0) ;
dsu(1 , 0 , 1) ;
for(int i = 1; i <= m ;i ++ )
printf("%d\n" , ans[i]) ;
return 0 ;
}
int main()
{
// freopen("C://Users//spnooyseed//Desktop//in.txt" , "r" , stdin) ;
// freopen("C://Users//spnooyseed//Desktop//out.txt" , "w" , stdout) ;
work() ;
return 0 ;
}
/*
*/
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。