• Codeforces 519 E. A and B and Lecture Rooms


    Description

    询问一个树上与两点距离相等的点的个数.

    Sol

    倍增求LCA.

    一棵树上距离两点相等,要么就只有两点的中点,要么就是与中点相连的所有点.

    有些结论很容易证明,如果距离是偶数,那么他们没有中点,树上不存在距离两点相等的点.

    如果中点恰好是两点LCA,那么答案就是(n-size_x-size_y) ,(size_x) 和 (size_y) 表示LCA的子节点中子树包含 (u,v) 的子节点的(size)

    如果不是LCA,那么答案就是 (size_{LCA}-size_x) 是深度靠下的点.

    PS:Loli的破机子跑的真tm慢.

    Code

    #include<cstdio>
    #include<utility>
    #include<vector>
    #include<iostream>
    using namespace std;
    
    #define mpr(a,b) make_pair(a,b)
    #define debug(a) cout<<#a<<"="<<a<<" "
    const int N = 100005;
    const int M = 21;
    
    int n;
    int f[N][M],d[N],sz[N],pow2[M];
    vector<int> g[N];
    
    inline int in(int x=0,char ch=getchar()){ while(ch>'9'|| ch<'0') ch=getchar();
    	while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x; }
    void DFS(int u,int fa,int dep){
    	f[u][0]=fa,sz[u]=1,d[u]=dep;
    	for(int i=0,v;i<g[u].size();i++) if((v=g[u][i])!=fa){
    		DFS(v,u,dep+1);
    		sz[u]+=sz[v];
    	}
    }
    pair<int,int> LCA(int u,int v){
    	if(d[u]<d[v]) swap(u,v);
    	int l=d[u]-d[v],res=0;
    	for(int i=0;i<M;i++){
    		if(l&pow2[i]) res=res+pow2[i],u=f[u][i];
    	}
    	if(u==v) return mpr(res,u);
    	for(int i=M-1;~i;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i],res+=pow2[i]*2;
    	return mpr(res+2,f[u][0]);
    }
    int Getp(int u,int d){
    	for(int i=0;i<M;i++) if(d & pow2[i]) u=f[u][i];
    	return u;
    }
    void solve(int u,int v){
    	if(d[u]<d[v]) swap(u,v);
    	pair<int,int> pr=LCA(u,v);
    	
    //	debug(pr.first),debug(pr.second)<<endl;
    	
    	if(u==v){ printf("%d
    ",n);return; }
    	if(pr.first & 1){ printf("%d
    ",0);return; }
    	
    	int mid=Getp(u,pr.first/2);
    	int uu=Getp(u,pr.first/2-1),vv=Getp(v,pr.first/2-1);
    	
    //	debug(mid),debug(uu),debug(vv)<<endl;
    	
    	if(mid == pr.second){
    		printf("%d
    ",n-sz[uu]-sz[vv]);
    	}else{
    		printf("%d
    ",sz[mid]-(f[uu][0]==mid ? sz[uu] : 0) - (f[vv][0]==mid ? sz[vv] : 0));
    	}
    }
    int main(){
    	
    	n=in();
    	for(int i=1,u,v;i<n;i++) u=in(),v=in(),g[u].push_back(v),g[v].push_back(u);
    	pow2[0]=1;for(int i=1;i<M;i++) pow2[i]=pow2[i-1]<<1;
    	
    	DFS(1,0,1);
    	for(int j=1;j<M;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
    	
    	for(int m=in(),u,v;m--;) u=in(),v=in(),solve(u,v);
    	return 0;
    }
    

      

  • 相关阅读:
    构建简单的二叉树(C)
    C指針淺析(3)
    C語言函數
    C# 細節(2)
    如何做好软件架构设计
    C# 細節(1)
    .NET Framework格式化字符串
    Windows下通过删除硬盘分区直接强行移除Fedora后恢复Windows启动项的方法
    DreamWeaver使用技巧学习心得
    MyEclipse使用心得、快捷键、设置
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6013925.html
Copyright © 2020-2023  润新知