zoukankan      html  css  js  c++  java
  • 题解 CF208E 【Blood Cousins】

    无任何高级数据结构。

    本题分为两部分:

    1. 一部分是求出树上 (k) 级祖先,直接倍增跳就可以。

    2. 另一部分是求出树上 (k) 级子孙的数量,这一部分比较复杂。

      首先一个点的 (k) 级子孙的深度显然都是一样的,因为是在同一子树内,所以,如果我们把 (dep)(x) 的点的 (dfs) 序从小到大存起来就会发现它们是连续的。

      把它们存起来之后,问题就变成了统计一个单调递增的序列中数值在 (lsim r) 内的数的个数。这个问题我们可以二分解决,我们可以二分出小于 (r) 的数的最大的位置,求出可行答案的右端点,再二分出左端点就可以了。

    #include<bits/stdc++.h>
    #define log(a) cerr<<"33[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"33[0m"<<endl
    #define LL long long
    #define SZ(x) ((int)x.size()-1)
    #define ms(a,b) memset(a,b,sizeof a)
    #define F(i,a,b) for(int i=(a);i<=(b);++i)
    #define DF(i,a,b) for(int i=(a);i>=(b);--i)
    using namespace std;
    inline int read(){char ch=getchar(); int w=1,c=0;
    	for(;!isdigit(ch);ch=getchar()) if (ch=='-') w=-1;
    	for(;isdigit(ch);ch=getchar()) c=(c<<1)+(c<<3)+(ch^48);
    	return w*c;
    }
    template<typename T>inline void write(T x){
        unsigned long long y=0;T l=0;
        if(x<0)x=-x,putchar(45);
        if(!x){putchar(48);return;}
        while(x){y=y*10+x%10;x/=10;l++;}
        while(l){putchar(y%10+48);y/=10;l--;}
    }
    template<typename T>inline void writeln(T x){write(x);puts("");}
    template<typename T>inline void writes(T x){write(x);putchar(32);}
    const int N=1e6+10;
    int fa[10][N],dep[N],cnt,l[N],r[N],h[N],a[N],t[N],tot,hd[N],nxt[N],to[N];
    inline void add(int x,int y){
    	to[++tot]=y;
    	nxt[tot]=hd[x];
    	hd[x]=tot;
    }
    void dfs(int x){
    	l[x]=++cnt;
    	a[x]=++h[dep[x]];
    	for(int i=hd[x];i;i=nxt[i])dfs(to[i]);
    	r[x]=cnt;
    }
    signed main(){
    	int n=read();
    	F(i,1,n){
    		fa[0][i]=read();
    		if(!fa[0][i]){
    			dep[i]=1;
    			continue;
    		}
    		add(fa[0][i],i);
    		dep[i]=dep[fa[0][i]]+1;
    		F(j,1,9)fa[j][i]=fa[j-1][fa[j-1][fa[j-1][fa[j-1][i]]]];
    	}
    	F(i,1,n)
    		if(!fa[0][i])dfs(i);
    	F(i,2,n)h[i]+=h[i-1];
    	F(i,1,n)t[h[dep[i]-1]+a[i]]=l[i];
    	int q=read();
    	while(q--){
    		int x=read(),k=read(),z=dep[x];
    		DF(i,9,0){
    			int z=(1<<(i<<1));
    			if(k>=z)k-=z,x=fa[i][x];
    			if(k>=z)k-=z,x=fa[i][x];
    			if(k>=z)k-=z,x=fa[i][x];
    		}
    		int l=h[z-1],r=h[z]+1;
    		while(l+1<r){
    			int mid=(l+r)>>1;
    			if(mid<0)break;
    			if(t[mid]<::l[x])l=mid;
    			else r=mid;
    		}
    		int kl=l+1,kr=h[z]+1;
    		while(kl+1<kr){
    			int kmid=(kl+kr)>>1;
    			if(t[kmid]<=::r[x])kl=kmid;
    			else kr=kmid;
    		}
    		writes(kl-l-1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux系统挂载点与分区的关系(转载)
    读书笔记深入linux内核架构Chapter 2 part2
    读书笔记深入linux内核架构Chapter 2 part1
    读书笔记深入linux内核架构Chapter9
    读书笔记深入linux内核架构Chapter8part2
    鞋匠的烦恼
    和最大的连续子数组
    wxLog 的使用
    suffix trie
    trie
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/15109745.html
Copyright © 2011-2022 走看看