zoukankan      html  css  js  c++  java
  • CF208E Blood Cousins

    洛咕

    题意:给你一片森林,每次询问一个点与多少个点拥有共同的(K)级祖先.(n,m<=100000.)

    分析:先不管森林不森林的(森林就当做多棵独立的树来处理就好了,反正产生的贡献相互不影响),在一棵树上,我们要维护每个点有多少个点的深度与之相同,空间是开不下的.所以我们需要稍微转化一下,维护每个点的深度为(K)的儿子有多少个.所以我们先通过(LCA)找到节点(x)(K)级祖先(y),然后把((y,dep[u]))当做一组询问,表示要查询(y)的子树中深度为(dep[u])的儿子的数量.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=1e5+5;
    int n,m;
    int f[N][20],visit[N],sum[N],ans[N];
    int dep[N],root[N],size[N],son[N];
    int tot,head[N],nxt[N],to[N],Head[N];
    inline void add(int a,int b){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;}
    struct query{int dep,nxt;}a[N];
    void Add(int x,int d,int id){a[id]=(query){d,Head[x]};Head[x]=id;}
    inline void pre_dfs(int u){
    	size[u]=1;
    	for(int j=1;j<=18;++j)f[u][j]=f[f[u][j-1]][j-1];
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];dep[v]=dep[u]+1;f[v][0]=u;
    		pre_dfs(v);size[u]+=size[v];
    		if(size[v]>size[son[u]])son[u]=v;
    	}
    }
    inline void update(int u,int val){
    	sum[dep[u]]+=val;
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];if(visit[v])continue;
    		update(v,val);
    	}
    }
    inline void dfs(int u,int keep){
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];if(v==son[u])continue;
    		dfs(v,0);
    	}
    	if(son[u])dfs(son[u],1),visit[son[u]]=1;update(u,1);
    	for(int i=Head[u];i;i=a[i].nxt)ans[i]=sum[a[i].dep]-1;
    	visit[son[u]]=0;if(!keep)update(u,-1);
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;++i){
    		int x=read();
    		if(!x)root[++root[0]]=i,dep[i]=1;
    		else add(x,i);
    	}
    	for(int i=1;i<=root[0];++i)pre_dfs(root[i]);
    	m=read();
    	for(int i=1;i<=m;++i){
    		int x=read(),k=read(),d=dep[x];
    		for(int j=0;j<=18;++j)if(k&(1<<j))x=f[x][j];
    		Add(x,d,i);//转化询问方式
    	}
    	for(int i=1;i<=root[0];++i)dfs(root[i],0);
    //我写上面分析森林的时候理解了为什么本题中keep要初始化为0
    //因为每棵树是互相独立的,所以每棵树产生的贡献都要被清除
    	for(int i=1;i<=m;++i)printf("%d
    ",ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    Git
    linux下利用virtualenv搭建虚拟环境
    Session和Cookie
    Redis
    从零开始学Go之基本(二):包、函数声明与格式化输出
    从零开始学Go之HelloWorld
    C++ vector容器使用
    FIRST集和FOLLOW集的计算
    go编译错误:runnerw.exe:CreateProcess failed with error 216:
    Linux下vi编辑器常用命令
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11666831.html
Copyright © 2011-2022 走看看