1151 LCA in a Binary Tree (30 point(s))

本文深入解析了二叉树中寻找两个节点的最低公共祖先(LCA)的算法,提供了详细的实现步骤,包括根据先序和中序遍历序列重建二叉树、节点存储策略以及通过回溯查找LCA的方法。

1151 LCA in a Binary Tree (30 point(s))

The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.

Given any two nodes in a binary tree, you are supposed to find their LCA.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is guaranteed that the binary tree can be uniquely determined by the input sequences. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of int.

Output Specification:

For each given pair of U and V, print in a line LCA of U and V is A. if the LCA is found and A is the key. But if A is one of U and V, print X is an ancestor of Y. where X is A and Y is the other node. If U or V is not found in the binary tree, print in a line ERROR: U is not found. or ERROR: V is not found. or ERROR: U and V are not found..

Sample Input:

6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99

Sample Output:

LCA of 2 and 6 is 3.
8 is an ancestor of 1.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.

 LCA(最低公共祖先结点)。

注意点:

1. 结点的静态存储。

2. 树的重建,获得所在层次和父亲结点。

思路:

1. 先根据先序遍历和中序遍历重建树,注意保存结点的父亲结点下标所在层次。树的存储采取静态方式,方便通过结点的值找到结点。

2. 然后根据根据给出数对的数据找到这两个结点。

3. 注意到每一个非根结点的父亲结点是唯一的。将较低的结点向上回溯,直到所在的层次一样,如果此时就相等的,说明较高的结点是较低结点的祖先;否则同时回溯,直到结点相同。

参考链接:https://blog.youkuaiyun.com/richenyunqi/article/details/79839484

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int M,N;
const int MAX = 1e4+7;
struct Node{
	int data;int level;int father;//由于需要回溯,保存结点的父亲结点的下标(前序遍历的位置)和层次 
	Node(int d=0,int l=0,int f=-1):data(d),level(l),father(f){} 
};
Node pre[MAX];//结点静态存储 
int in[MAX];
void createTree(int root,int left,int right,int father,int level){
	//根据前序遍历的root位置和中序遍历的left和right的区间重建树 
	if(left>right) return;
	pre[root] =  Node(pre[root].data,level,father);
	int index = left;
	while(pre[root].data!=in[index]) index++;
	createTree(root+1,left,index-1,root,level+1);
	createTree(root+1+index-left,index+1,right,root,level+1);
}
int main(void){
	cin>>M>>N;
	for(int i=0;i<N;i++) cin>>in[i];
	for(int i=0;i<N;i++) cin>>pre[i].data;
	createTree(0,0,N-1,-1,0);
	int a,b;
	for(int i=0;i<M;i++){
		cin>>a>>b;
		int ai=N;int bi=N;
		for(int i=0;i<N;i++){//根据数据查询结点的下标 
			if(a==pre[i].data) ai = i;
			if(b==pre[i].data) bi = i;
		}
		if(ai==N&&bi==N) printf("ERROR: %d and %d are not found.\n",a,b);
		else if(ai==N&&bi!=N) printf("ERROR: %d is not found.\n",a);
		else if(ai!=N&&bi==N) printf("ERROR: %d is not found.\n",b);
		else{
			bool deeper = true;//Node a is deeper;
			if(pre[ai].level<pre[bi].level){
				deeper = false;
				swap(ai,bi);
			}
			while(pre[ai].level!=pre[bi].level) ai = pre[ai].father;//使得两个结点深度相同 
			if(ai==bi){
				printf("%d is an ancestor of %d.\n",(deeper?b:a),(deeper?a:b));//如果此时两个结点到了同一层 
			}
			else{
				while(ai!=bi){//否则同时向上回溯 
					ai = pre[ai].father;
					bi = pre[bi].father;
				}
				printf("LCA of %d and %d is %d.\n",a,b,pre[ai].data);
			}
		}
	}
	return 0;
}

 

//#pragma GCC optimize(2,3,“Ofast”,“inline”, “-ffast-math”) //#pragma GCC target(“avx,sse2,sse3,sse4,mmx”) #include #include #include #include #include #include #include #include #include<unordered_map> #include #include #include #include #include #include #include #define fi first #define se second #define pb push_back #define y1 hsduaishxu #define mkp make_pair using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,int> pli; typedef pair<int,ll> pil; typedef pair<ll,ll> pll; typedef unsigned int uint; typedef vector vpii; typedef int128 i128; const int maxn=1000005; const ll mod=1000000007; inline int Min(int x,int y){return x<y?x:y;} inline int Max(int x,int y){return x>y?x:y;} inline ll Min(ll x,ll y){return x<y?x:y;} inline ll Max(ll x,ll y){return x>y?x:y;} inline void ad(int &x,int y,int z){x=y+z;if(x>=mod) x-=mod;} inline void ad(ll &x,ll y,ll z){x=y+z;if(x>=mod) x-=mod;} inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;} inline void ad(int &x,ll y){x+=y;if(x>=mod) x-=mod;} inline void ad(ll &x,ll y){x+=y;if(x>=mod) x-=mod;} inline void siu(int &x,int y,int z){x=y-z;if(x<0) x+=mod;} inline void siu(int &x,int y){x-=y;if(x<0) x+=mod;} inline void siu(ll &x,ll y){x-=y;if(x<0) x+=mod;} inline ll myabs(ll x){return x<0?-x:x;} inline void tmn(int &x,int y){if(y<x) x=y;} inline void tmx(int &x,int y){if(y>x) x=y;} inline void tmn(ll &x,ll y){if(y<x) x=y;} inline void tmx(ll &x,ll y){if(y>x) x=y;} ll qpow(ll aa,ll bb){ll res=1;while(bb){if(bb&1) res=resaa%mod;aa=aaaa%mod;bb>>=1;}return res;} ll qpow(ll aa,ll bb,ll md){ll res=1;while(bb){if(bb&1) res=(i128)resaa%md;aa=(i128)aaaa%md;bb>>=1;}return res;} inline ll Inv(ll x,ll md){return qpow(x,md-2,md);} inline ll Inv(ll x){return qpow(x,mod-2);} int ,; int n,k; int p[maxn],q[maxn]; ll ans; vector g[maxn],h[maxn]; int r1,r2; int siz[maxn],dfn[maxn],dfscnt; void dfs(int u) { siz[u]=1;dfn[u]=dfscnt; for(auto v:g[u]) dfs(v),siz[u]+=siz[v]; } struct bit { int c[maxn]; void clr() { for(int i=1;i<=n;i) c[i]=0; } int lowbit(int x){return x&(-x);} void ad(int x,int k){while(x<=n){c[x]+=k;x+=lowbit(x);}} int qry(int x){int res=0;while(x>=1){res+=c[x];x-=lowbit(x);}return res;} }T1,T2; int F[maxn],st[maxn],tp,sz[maxn],son[maxn]; vector e[maxn]; void dfs1(int u) { st[tp]=u;e[u].clear(); if(tp>k) F[u]=st[tp-k]; else F[u]=0; if(F[u]) e[F[u]].push_back(u); sz[u]=1;son[u]=0; for(auto v:h[u]) { dfs1(v); if(sz[v]>sz[son[u]]) son[u]=v; sz[u]+=sz[v]; } tp–; } void ins(int x,int k) { T1.ad(dfn[x],k);T1.ad(dfn[x]+siz[x],-k); T2.ad(dfn[x],k); } int qry(int x) { return T1.qry(dfn[x])+T2.qry(dfn[x]+siz[x]-1)-T2.qry(dfn[x]-1); } void dfs3(int u,int ty) { for(auto v:e[u]) { if(ty1) ans+=qry(v); else if(ty3) ins(v,-1); else if(ty==2) ins(v,1); } for(auto v:h[u]) dfs3(v,ty); } void dfs2(int u,int ty) { for(auto v:h[u]) if(v!=son[u]) dfs2(v,0); if(son[u]) { dfs2(son[u],1); for(auto v:h[u]) if(v!=son[u]) dfs3(v,1),dfs3(v,2); } for(auto v:e[u]) ins(v,1); if(!ty) dfs3(u,3); } void cal() { dfscnt=0;dfs(r1); T1.clr();T2.clr(); tp=0;dfs1(r2); dfs2(r2,0); } void solve() { cin>>n>>k; for(int i=1;i<=n;i) cin>>p[i]; for(int i=1;i<=n;i++) cin>>q[i]; for(int i=1;i<=n;i++) { if(!p[i]) r1=i; else g[p[i]].push_back(i); if(!q[i]) r2=i; else h[q[i]].push_back(i); } cal(); for(int i=1;i<=n;i++) swap(p[i],q[i]),swap(g[i],h[i]);swap(r1,r2); cal(); cout<<ans<<“\n”; } signed main() { freopen(“D.in”,“r”,stdin); freopen(“D.out”,“w”,stdout); ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); =1; //cin>>; while(–) { solve(); } return 0; } //by cristiano ronaldo dos santos aveiro #include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i,s,t) for(register ll i = s;i <= t;++i) #define per(i,t,s) for(register ll i = t;i >= s;–i) const ll N = 1e6 + 5; ll n; ll k; ll rt1; ll rt2; ll top; ll idx; ll ans; ll p[N] = {}; ll q[N] = {}; ll fa[N] = {}; ll st[N] = {}; ll sz[N] = {}; ll siz[N] = {}; ll dfn[N] = {}; ll son[N] = {}; vector g[N]; vector g1[N]; vector g2[N]; class binary_indexed_tree { private: ll t[N] = {}; public: inline void init() { memset(t,0,sizeof(t)); } inline ll lowbit(ll x) { return x & (-x); } inline void upd(ll x,ll k) { while(x <= n) { t[x] += k; x += lowbit(x); } } inline ll qry(ll x) { ll ans = 0; while(x) { ans += t[x]; x -= lowbit(x); } return ans; } }; binary_indexed_tree t1; binary_indexed_tree t2; inline ll read() { ll x = 0; ll y = 1; char c = getchar(); while(c < ‘0’ || c > ‘9’) { if(c == ‘-’) y = -y; c = getchar(); } while(c >= ‘0’ && c <= ‘9’) { x = (x << 3) + (x << 1) + (c ^ ‘0’); c = getchar(); } return x * y; } inline void write(ll x) { if(x < 0) { putchar(‘-’); write(-x); return; } if(x > 9) write(x / 10); putchar(x % 10 + ‘0’); } inline void dfs(ll u) { siz[u] = 1; dfn[u] = ++idx; for(register auto v : g1[u]) { dfs(v); siz[u] += siz[v]; } } inline void dfs1(ll u) { st[++top] = u; g[u].clear(); if(top > k) fa[u] = st[top - k]; else fa[u] = 0; if(fa[u]) g[fa[u]].push_back(u); sz[u] = 1; son[u] = 0; for(auto v : g2[u]) { dfs1(v); if(sz[v] > sz[son[u]]) son[u] = v; sz[u] += sz[v]; } top–; } inline void ins(ll x,ll k) { t1.upd(dfn[x],k); t1.upd(dfn[x] + siz[x],-k); t2.upd(dfn[x],k); } inline ll query(ll x) { return t1.qry(dfn[x]) + t2.qry(dfn[x] + siz[x] - 1) - t2.qry(dfn[x] - 1); } inline void dfs3(ll u,ll k) { for(auto v : g[u]) { if(k == 1) ans += query(v); else if(k == 2) ins(v,1); else if(k == 3) ins(v,-1); } for(auto v : g2[u]) dfs3(v,k); } inline void dfs2(ll u,ll k) { for(auto v : g2[u]) if(v != son[u]) dfs2(v,0); if(son[u]) { dfs2(son[u],1); for(auto v : g2[u]) { if(v != son[u]) { dfs3(v,1); dfs3(v,2); } } } for(register auto v : g[u]) ins(v,1); if(!k) dfs3(u,3); } int main() { freopen(“D.in”,“r”,stdin); freopen(“D.out”,“w”,stdout); n = read(); k = read(); rep(i,1,n) p[i] = read(); rep(i,1,n) q[i] = read(); rep(i,1,n) { if(!p[i]) rt1 = i; else g1[p[i]].push_back(i); if(!q[i]) rt2 = i; else g2[q[i]].push_back(i); } idx = 0; dfs(rt1); t1.init(); t2.init(); top = 0; dfs1(rt2); dfs2(rt2,0); rep(i,1,n) { swap(p[i],q[i]); swap(g1[i],g2[i]); swap(rt1,rt2); } idx = 0; dfs(rt1); t1.init(); t2.init(); top = 0; dfs1(rt2); dfs2(rt2,0); write(ans); fclose(stdin); fclose(stdout); return 0; }针对以下问题,上述两段代码的功能有什么不同,请指出并修正第二段代码,使得第二段代码功能与第一段代码功能完全等价小丁的树 题目描述 小丁拥有两棵均具有 n n 个顶点,编号集合为 { 1 , 2 , ⋯ &thinsp; , n } {1,2,⋯,n} 的有根树 T 1 , T 2 T 1 ​ ,T 2 ​ ,现在他需要计算这两棵树的相似程度。 为了计算,小丁定义了对于一棵树 T T 和 T T 上两个不同顶点 u , v u,v 的距离函数 d T ( u , v ) d T ​ (u,v),其定义为 u , v u,v 两个点距离成为祖先关系有多近,具体来说,对于所有在 T T 上为祖先关系的点对 ( u ′ , v ′ ) (u ′ ,v ′ ), dis ⁡ ( u , u ′ ) + dis ⁡ ( v , v ′ ) dis(u,u ′ )+dis(v,v ′ ) 的最小值即为 d T ( u , v ) d T ​ (u,v) 的值,其中 dis ⁡ ( u , v ) dis(u,v) 表示 u , v u,v 在树 T T 上的唯一简单路径包含的边数,即 u , v u,v 的距离。 点对 ( u ′ , v ′ ) (u ′ ,v ′ ) 为祖先关系,当且仅当 u ′ u ′ 是 v ′ v ′ 的祖先或 v ′ v ′ 是 u ′ u ′ 的祖先。(注意,每个点都是自己的祖先) 小丁心里还有一个参数 k k,如果节点对 ( u , v ) (u,v) 满足以下条件,称之为不相似的节点对: 1 ≤ u < v ≤ n 1≤u<v≤n " d T 1 ( u , v ) 0 d T 1 ​ ​ (u,v)=0 且 d T 2 ( u , v ) k d T 2 ​ ​ (u,v)>k“ 或 " d T 2 ( u , v ) 0 d T 2 ​ ​ (u,v)=0 且 d T 1 ( u , v ) k d T 1 ​ ​ (u,v)>k​“ 小丁认为,不相似的节点对越多, T 1 T 1 ​ 和 T 2 T 2 ​ 就越不相似,你能告诉他总共有多少不相似的节点对吗? 输入格式 第一行两个整数 n , k n,k,表示 T 1 T 1 ​ 和 T 2 T 2 ​ 的节点数和参数 k k。 第二行 n n 个正整数 p 1 , p 2 , ⋯ &thinsp; , p n p 1 ​ ,p 2 ​ ,⋯,p n ​ , T 1 T 1 ​ 中节点 i i 的父节点为 p i p i ​ ,特别的,若 p i 0 p i ​ =0,则 i i 是 T 1 T 1 ​ 的根。 第三行 n n 个正整数 q 1 , q 2 , ⋯ &thinsp; , q n q 1 ​ ,q 2 ​ ,⋯,q n ​ , T 2 T 2 ​ 中节点 i i 的父节点为 q i q i ​ ,特别的,若 q i 0 q i ​ =0,则 i i 是 T 2 T 2 ​ 的根。 输出格式 一行一个整数,表示不相似的节点对总数。 样例 1 输入 5 0 0 1 1 2 3 5 3 1 1 0 样例 1 输出 4 样例 1 解释 ( 2 , 3 ) , ( 2 , 4 ) , ( 2 , 5 ) , ( 4 , 5 ) (2,3),(2,4),(2,5),(4,5) 为不相似的节点对。 其余样例见下发文件。 数据规模与约定 对于所有数据, 1 ≤ n ≤ 2 × 10 5 , 0 ≤ k < n , 0 ≤ p i , q i ≤ n 1≤n≤2×10 5 ,0≤k<n,0≤p i ​ ,q i ​ ≤n,且由 p i , q i p i ​ ,q i ​ 形成的是一棵 n n 个节点的有根树。 本题采用捆绑评测,你只有通过了一个子任务中所有测试点才能得到该子任务的分数。 Subtask 1(10pts): 1 ≤ n ≤ 100 1≤n≤100。 Subtask 2(20pts): 1 ≤ n ≤ 3000 1≤n≤3000。 Subtask 3(20pts): k 0 k=0。 Subtask 4(10pts): 0 ≤ k ≤ 20 0≤k≤20。 Subtask 5(40pts):无特殊限制。
最新发布
07-25
<think>好的,我现在需要解决用户在SAS PROC LCA中使用协变量时不报告BIC和熵值的问题。首先,我需要回忆一下PROC LCA的相关知识,特别是当模型中加入协变量时的输出变化。 用户提到,当包含协变量时,PROC LCA默认不显示BIC和熵值。这可能是因为协变量的加入改变了模型的结构,导致这些指标的计算方式不同或者需要额外设置才能输出。我需要确认PROC LCA在处理协变量时的默认行为,以及是否有选项可以启用这些统计量。 首先,BIC(贝叶斯信息准则)和熵值通常用于评估潜类别模型的拟合优度和分类质量。在基础的无协变量LCA模型中,PROC LCA默认会报告这些指标。但当加入协变量后,模型变成了带有协变量的潜类别模型,可能属于LCR(潜类别回归)模型。这时候,模型评估指标可能会有所变化,或者需要特定的输出请求。 查阅SAS文档或相关资料,发现当在PROC LCA中使用协变量时,默认的输出可能不会包含BIC和熵值。这是因为协变量模型(如LCR)的参数估计和模型拟合指标的计算方法不同,可能依赖于条件概率,导致熵值等指标的意义发生变化。因此,可能需要通过特定的选项或语句来请求这些统计量。 可能的解决方法是检查PROC LCA的语法,看看是否有选项可以强制输出这些指标。例如,使用“OUTPOST”选项输出后验概率,然后手动计算熵值。对于BIC,可能需要查看输出日志或结果中的其他拟合统计量,或者通过MODEL语句的选项来启用。 另外,用户可能需要确认是否在正确的语句中指定了协变量。例如,协变量应该在MODEL语句中使用COVS选项指定。如果语法有误,可能导致输出不完整。此外,查看是否有最新的SAS版本或是否有已知的问题,可能需要更新或应用补丁。 总结可能的解决步骤: 1. 检查PROC LCA的语法是否正确,特别是协变量的指定方式。 2. 使用OUTPOST选项输出后验概率,手动计算熵值。 3. 查看输出中是否有其他拟合指标,如AIC,并确认BIC是否被其他统计量替代。 4. 考虑使用%LCA_Bootstrap宏或其他辅助宏来获取更多统计量。 5. 参考SAS官方文档或用户论坛,寻找相关问题的解决方案。 用户可能需要手动计算熵值,公式为:熵 = 1 - (Σ(后验概率 * ln(后验概率)))/(n * ln(K)),其中n是样本数,K是类别数。而BIC可能需要从模型拟合统计中提取,或者通过公式计算。 此外,建议用户检查是否在MODEL语句中正确指定了协变量,并确保数据格式正确。如果问题依旧,可能需要联系SAS技术支持或查阅相关文献中的示例代码,看是否有遗漏的选项。 最后,生成相关问题,帮助用户深入理解PROC LCA的使用和潜类别分析中的模型评估方法。</think>在SAS PROC LCA中包含协变量时,BIC和熵值默认不报告的原因在于**协变量模型(LCR)的评估指标计算方法与基础LCA不同**。以下是具体解决方案及操作步骤: --- ### **解决方案分步说明** 1. **手动计算熵值** 使用`OUTPOST`选项输出后验概率,通过以下公式计算熵值: $$ \text{熵} = 1 - \frac{\sum_{i=1}^n \sum_{k=1}^K p_{ik} \ln(p_{ik})}{n \ln(K)} $$ - 其中 $p_{ik}$ 是第 $i$ 个观测属于第 $k$ 个类别的后验概率,$n$ 为样本量,$K$ 为潜类别数。 **代码示例**: ```sas PROC LCA DATA=your_data OUTPOST=posterior_prob; NCLASS 3; # 假设分为3个类别 ITEMS item1 item2 item3; COVS cov1 cov2; # 指定协变量 CATEGORIES 2 2 2; RUN; DATA entropy; SET posterior_prob; entropy_contribution = -p1*LOG(p1) - p2*LOG(p2) - p3*LOG(p3); # 根据实际类别数调整 RUN; PROC MEANS DATA=entropy SUM; VAR entropy_contribution; RUN; ``` 2. **获取BIC值** BIC值通常可在输出日志或`MODEL FIT`部分找到。若未显示,尝试以下方法: - 在`PROC LCA`语句中添加`FITSTATS`选项强制输出拟合指标。 - 使用公式手动计算: $$ \text{BIC} = -2 \ln(L) + d \ln(n) $$ 其中 $L$ 是模型似然值,$d$ 为参数总数,$n$ 为样本量。 3. **使用宏扩展功能** SAS的`%LCA_Bootstrap`宏可提供更详细的统计量。需从SAS官方支持页面下载并加载宏[^1]。 --- ### **关键注意事项** - **语法验证**:确保协变量在`COVS`语句中正确声明,且数据格式符合要求(分类协变量需预处理)。 - **版本兼容性**:SAS 9.4及更高版本对LCR模型支持更完善,建议更新至最新版本。 - **替代方案**:若仍无法获取指标,可考虑使用`PROC LTA`(潜转变分析)或第三方包(如R的`poLCA`)。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值