E

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]))<< "
";
  } 
  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
" , 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 ;
}
/*

*/
	
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
原文地址:https://www.cnblogs.com/spnooyseed/p/14824774.html