首页 > 其他分享 >[题解]P6374 「StOI-1」树上询问

[题解]P6374 「StOI-1」树上询问

时间:2024-06-08 23:55:27浏览次数:16  
标签:dep siz int 题解 P6374 jump fa StOI lca

题意简述

给定一个\(N\)个节点的树,接下来有\(q\)次询问。每次询问给定\(a,b,c\),请问存在多少个节点\(i\),使得这棵树在以\(i\)为根的情况下,\(a\)和\(b\)的LCA是\(c\)。

解题思路

首先通过分析样例,我们发现:\(a,b\)的LCA一定在它们之间的简单路径上,所以如果\(c\)不在\(a,b\)之间的简单路径上,则输出\(0\)。

进一步分析\(c\)在\(a,b\)间简单路径上的情况,我们可以归纳出三种情况:

  • 如果\(c=lca(a,b)\),那么答案是\(n-siz[jump(a,c)]-siz[jump(b,c)]\),其中\(siz[u]\)表示以\(u\)为根的子数大小,\(jump(u,v)\)表示\(u\)点向上跳到\(v\)的下一层所到达的节点。
  • 如果\(c\)在\(a\)到\(lca(a,b)\)的路径上,那么答案是\(siz[c]-siz[jump(a,c)]\)。
  • 如果\(c\)在\(b\)到\(lca(a,b)\)的路径上,那么答案是\(siz[c]-siz[jump(b,c)]\)。

接下来我们思考代码实现。怎样知道\(c\)是哪一种情况呢?

  • 第一种情况:\(c=lca(a,b)\)。
  • 第二种情况:\(lca(a,c)=c\)且\(lca(a,b)=lca(b,c)\)。
  • 第三种情况:\(lca(b,c)=c\)且\(lca(a,b)=lca(a,c)\)。

代码实现中,\(jump()\)函数我们可以通过倍增的思想在\(O(\log N)\)的时间复杂度内完成。而求\(lca()\)函数同样可以用倍增达到\(O( \log N)\)的时间复杂度。

点击查看代码
#include<bits/stdc++.h>
#define N 500010
using namespace std;
int n,q,dep[N],fa[N][20],siz[N];
vector<int> G[N];
void dfs(int u,int father){
	siz[u]=1;
	dep[u]=dep[father]+1;
	fa[u][0]=father;
	for(int i=1;i<20;i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i:G[u])
		if(i!=father) dfs(i,u),siz[u]+=siz[i];
}
int lca(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);
	for(int i=19;i>=0;i--)
		if(dep[fa[u][i]]>=dep[v])
			u=fa[u][i];
	if(u==v) return v;
	for(int i=19;i>=0;i--)
		if(fa[u][i]!=fa[v][i])
			u=fa[u][i],v=fa[v][i];
	return fa[u][0];
}
int jump(int a,int b){
	if(dep[a]==dep[b]) return 0;
	//计算a跳到b下一层的位置
	for(int i=19;i>=0;i--)
		if(dep[fa[a][i]]>dep[b])
			a=fa[a][i];
	return a;
}
int main(){
	cin>>n>>q;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		G[u].emplace_back(v);
		G[v].emplace_back(u);
	}
	dfs(1,0);
	while(q--){
		int a,b,c;
		cin>>a>>b>>c;
		int ab=lca(a,b),ac=lca(a,c),bc=lca(b,c);
		if(ab==c){
			cout<<n-siz[jump(a,c)]-siz[jump(b,c)]<<"\n";
		}else if(ac==c&&ab==bc){
			cout<<siz[c]-siz[jump(a,c)]<<"\n";
		}else if(bc==c&&ab==ac){
			cout<<siz[c]-siz[jump(b,c)]<<"\n";
		}else{
			cout<<"0\n";
		}
	}
	return 0;
}

标签:dep,siz,int,题解,P6374,jump,fa,StOI,lca
From: https://www.cnblogs.com/Sinktank/p/18238796

相关文章

  • CF1552G A Serious Referee 题解
    题目链接点击打开链接题目解法感觉很神奇的题首先把序列当成排列做首先发现只要当成\(01\)序列做就是对的为什么?你假设有数\(x<y\),你把\(\lex\)的数设成\(0\),\(>x\)且\(\ley\)的数设成\(1\),\(>y\)的数设成\(2\),然后做题目中的排序操作,如果最终序列形成逆序......
  • CF717G Underfail 题解
    题意:若干区间,区间有权值,选择一个子集,使得权值和尽量大并且每个点不被覆盖超过\(x\)次。\(n\le500\)思路:很神奇的一道题。我们考虑费用流,如果单纯的一边是区间一边是点的话其实并不好做,所以这道题我们直接建一排\(n+2\)个点,一个区间\(l,r\)就从\(l\)到\(r+1\)连......
  • CCF-GESP 等级考试 2023年9月认证C++四级真题解析
    一、单选题(每题2分,共30分)第1题⼈们所使⽤的⼿机上安装的App通常指的是()。A.⼀款操作系统B.⼀款应⽤软件C.⼀种通话设备D.以上都不对正确答案:B.⼀款应⽤软件解析:App是"Application"的缩写,中文意思是"应用",特指安装在智能手机上的第三方应用软件。这些软件通常......
  • 打砖块 题解
    题目链接\(50pts\)对于没有\(Y\)砖的情况,可以用分组背包解决,算出每一列打\(j\)块砖需要的子弹以及对分数的贡献,按照分组背包即可。对于包含\(Y\)砖的情况,不能直接分组背包解决。这实际上是打的顺序问题,比如:NYNY如果手上有两枚子弹,最优策略是先打掉第二列,再打掉第......
  • 【Selenium+java环境配置】(超详细教程常见问题解决)
    Selenium+java环境配置windows电脑环境搭建-chrome浏览器1.下载chrome浏览器2.查看chrome浏览器版本3.下载chrome浏览器驱动4.配置系统环境变量PATH验证环境是否搭建成功1.创建java项目,添加pom文件中添加依赖2.编写代码运行常见问题&解决办法1.访问失败Theversio......
  • 猜排列 题解
    猜排列题解差eps步想到正解。题意描述有\(m\)个长为\(n\)序列\(a_1,\dots,a_n\),还有\(m\)个长为\(n\)序列\(b_1,\dots,b_n\)。其中\(b_i\)是由\(a_i\)通过排列\(p\)置换得到的,\(b_{p_i}=a_i\)。现在又要求出排列\(p\)会有多种可能,模\(998244353\)。So......
  • P10466 邻值查找 题解
    题目传送门前置知识二叉搜索树&平衡树解法笔者写这篇题解的时候题面应该是出锅了,建议去看Acwing的题面。第一问同luoguP2234[HNOI2002]营业额统计,平衡树维护前驱、后继(非严格意义上的)求出差值后取\(\min\)即可;第二问用map实现一个映射即可维护位置。代码#incl......
  • P10499 开关问题 题解
    题目传送门前置知识高斯消元法解异或方程组|乘法原理解法把开关的相互影响关系转化成异或,然后就转化成了异或方程组,高斯消元求解即可。判断是否存在解的过程同luoguP2455[SDOI2006]线性方程组。由于自由元仅能取\(0/1\),故总方案数为\(2\)的自由元数量次方。代码......
  • P7219 [JOISC2020] 星座 3 题解
    会发现题目的坐标其实是平面直角坐标系。我们按\(y\)坐标从小到大考虑所有的星星,假设当前考虑到了星星\(i\)。我们先计算出之前所有能够影响到\(i\)的星星的代价和为\(cost\)(可以用树状数组维护)。然后分类讨论。若\(c_i\lecost\),那么肯定直接将\(i\)直接涂黑,因为它更......
  • P10560 [ICPC2024 Xi'an I] The Last Cumulonimbus Cloud 题解
    好好玩的题。思路对于一个图上邻域问题,我们有一个很经典的做法:根号分治。考虑根号分治的本质是什么。我们把点分成两类,平衡每一种点的时间,也就是度数大的与度数小的点。所以对于这道题,我们有了更加好的做法。发现题目给的图的性质就是一个天然的划分方案。我们每次找到图中......