• [Codeforces 208E] Blood Cousins(dsu on tree+倍增)


    [Codeforces 208E] Blood Cousins(dsu on tree+倍增)

    题面

    给出一个有根树森林,点集总大小为(n)。有(m)个询问,每个询问包含两个数(v_i,p_i),询问(v_i)(p_i)级祖先的子树内有多少和(v_i)深度相同

    分析

    先把询问离线。

    相同深度点的个数转化成:询问x子树内深度为k的个数-1.直接套dsu on tree板子,每个深度用一个变量计数。k级祖先用倍增求。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #define maxn 100000
    #define maxlogn 20
    using namespace std;
    int n,m;
    vector<int>E[maxn+5];
    bool is_root[maxn+5];
    inline void add_edge(int u,int v){
    	E[u].push_back(v);
    	E[v].push_back(u);
    }
    
    int deep[maxn+5];
    int anc[maxn+5][maxlogn+5];
    int fa[maxn+5],son[maxn+5],sz[maxn+5];
    void dfs1(int x,int f){
    	sz[x]=1;
    	fa[x]=f;
    	anc[x][0]=f;
    	deep[x]=deep[f]+1;
    	for(int i=1;i<=maxlogn;i++) anc[x][i]=anc[anc[x][i-1]][i-1];
    	for(int y : E[x]){
    		if(y!=f){
    			dfs1(y,x);
    			sz[x]+=sz[y];
    			if(sz[y]>sz[son[x]]) son[x]=y; 
    		}
    	}
    }
    inline int kth_anc(int x,int k){
    	for(int i=maxlogn;i>=0;i--){
    		if(k&(1<<i)) x=anc[x][i];
    	}
    	return x;
    }
    
    
    int cnt[maxn+5];
    bool vis[maxn+5];
    void calc(int x,int type){
    	cnt[deep[x]]+=type;
    	for(int y : E[x]){
    		if(!vis[y]&&y!=fa[x]) calc(y,type);
    	}
    }
    
    struct qtype{
    	int x;
    	int k;
    	int id; 
    	qtype(){
    		
    	}
    	qtype(int _x,int _k,int _id){
    		x=_x;
    		k=_k;
    		id=_id;
    	}
    };
    vector<qtype>q[maxn+5];
    int ans[maxn+5];
    void dfs2(int x,bool is_heavy){
    	for(int y : E[x]){
    		if(y!=fa[x]&&y!=son[x]){
    			dfs2(y,0);
    		}
    	}
    	if(son[x]){
    		dfs2(son[x],1);
    		vis[son[x]]=1;
    	}
    	calc(x,1);
    	vis[son[x]]=0;
    	for(qtype p : q[x]) ans[p.id]=cnt[deep[p.x]]-1;//记得减去自己 
    	if(!is_heavy) calc(x,-1);
    }
    
    int main(){
    	int f,x,k;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&f);
    		if(f!=0) add_edge(f,i);
    		else is_root[i]=1;
    	}
    	for(int i=1;i<=n;i++) if(is_root[i]) dfs1(i,0);
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		scanf("%d %d",&x,&k);
    		int z=kth_anc(x,k);
    		q[z].push_back(qtype(x,k,i));
    	}
    	
    	for(int i=1;i<=n;i++) if(is_root[i]) dfs2(i,0);
    	for(int i=1;i<=m;i++) printf("%d ",ans[i]);
    }
    
  • 相关阅读:
    (转)android头像设置:从本地照片库或拍照获取并剪裁
    获取短信验证码之后按钮背景变化并且出现倒计时
    欢迎界面的下方指示位置圆
    android 关于Toast重复显示解决方法
    判断是不是电话号码
    (转)根据ImageView的大小来压缩Bitmap,避免OOM
    (转)android屏幕适配
    GSON解析JSON
    Linux-命令-cut
    Linux-自疑惑
  • 原文地址:https://www.cnblogs.com/birchtree/p/12172201.html
Copyright © 2020-2023  润新知