• 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 ;
    }
    /*
    
    */
    	
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    4.0中的并行计算和多线程详解(一)
    Dojo工具包简介
    javascript中event.keyCode
    iText简介(转)
    ServletContext
    java文件加解密算法
    ResultSet 的相关介绍
    spring的AOP的四种实现方式
    java实现文件zip压缩或者解压缩
    Hibernate查询数据的几种方式以及HQL用法及参数的几种使用方法
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/14824774.html
Copyright © 2020-2023  润新知