• SP913 QTREE2


    洛咕

    题意:给定一棵(n(n<=10000))个点的树,边具有边权.要求以下操作:

    DIST a b 询问点a至点b路径上的边权之和.

    KTH a b k 询问点a至点b有向路径上的第k个点的编号.

    倍增水题???

    对于第一个询问,只要记录每个节点到根节点1的(dist),求出(LCA)之后,答案就是(dist[a]+dist[b]-2*dist[lca]).

    对于第二个询问,因为倍增求(LCA)的时候预处理出了(f[i][j])数组,表示i的(2^j)级祖先是谁,所以你只要分类讨论一下(a,b)的几种位置关系,倍增找就行了.

    #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=10005;
    int f[N][16],dep[N],dis[N];
    int tot,head[N],nxt[N<<1],to[N<<1],w[N<<1];
    inline void add(int a,int b,int c){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;w[tot]=c;}
    inline void dfs(int u,int fa){
    	for(int j=1;j<=15;++j)f[u][j]=f[f[u][j-1]][j-1];	
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];if(v==fa)continue;
    		dep[v]=dep[u]+1;f[v][0]=u;
    		dis[v]=dis[u]+w[i];dfs(v,u);
    	}
    }
    inline int LCA(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int j=15;j>=0;--j)
    		if(dep[f[x][j]]>=dep[y])x=f[x][j];
    	if(x==y)return x;
    	for(int j=15;j>=0;--j)
    		if(f[x][j]!=f[y][j])x=f[x][j],y=f[y][j];
    	return f[x][0];
    }
    int main(){
    	int T=read();
    	while(T--){
    		tot=0;memset(head,0,sizeof(head));
    		memset(f,0,sizeof(f));
    		memset(dis,0,sizeof(dis));
    		int n=read();
    		for(int i=1;i<n;++i){
    			int a=read(),b=read(),c=read();
    			add(a,b,c);add(b,a,c);
    		}
    		f[1][0]=1;dfs(1,0);
    		while(1){
    			string s;cin>>s;
    			if(s[1]=='I'){
    				int x=read(),y=read(),lca=LCA(x,y);if(!lca)lca=1;
    				printf("%d
    ",dis[x]+dis[y]-2*dis[lca]);
    			}
    			if(s[1]=='T'){
    				int x=read(),y=read(),k=read(),lca=LCA(x,y);if(!lca)lca=1;
    				--k;//根据题意,a点本身算是第一个节点,把它减掉
    				if(dep[x]-dep[lca]>=k){//这里包含了两种情况,一个是lca(x,y)=y,一个是x到lca的路径上超过k个点
    					for(int j=15;j>=0;--j)if(k&(1<<j))x=f[x][j];
    					printf("%d
    ",x);continue;
    				}
    				if(x==lca){//lca(x,y)=x,转换成y向上找
    					k=dep[y]-dep[x]-k;//转换一下
    					for(int j=15;j>=0;--j)if(k&(1<<j))y=f[y][j];
    					printf("%d
    ",y);continue;
    				}
    //否则就是一下这种情况,x到lca的路径上不足k个点,所以还需要转换之后y向上跳
    				k=k-(dep[x]-dep[lca]);k=dep[y]-dep[lca]-k;//先减掉x到lca的节点个数,再转换成y向上跳
    				for(int j=15;j>=0;--j)if(k&(1<<j))y=f[y][j];
    				printf("%d
    ",y);
    			}
    			if(s[1]=='O')break;
    		}
    	}
        return 0;
    }
    
    
  • 相关阅读:
    【IdentityServer4文档】- 整体情况
    【IdentityServer4文档】- 欢迎来到 IdentityServer4 (ASP.NET Core 3.x)
    证券相关基础概念
    [基于NetCore的简单博客系统]-登录
    JAVA mysql数据库 配置
    简单验证码识别及登陆并下载页面
    Java 无法初始化Connection的问题
    MUI scroll 定位问题
    CentOS7 安装 MySql
    ASP.NET CORE 2.0 文档中文正式版已经出来了
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11726378.html
Copyright © 2020-2023  润新知