1 条题解

  • 0
    @ 2025-11-12 16:46:06

    题目分析:

    我们需要在三角形网格上找到两个节点的最低公共祖先。关键观察是:

    1. 滑梯结构:三角形网格,第 r 层有 r+1 个节点
    2. 路径覆盖:所有滑行路径覆盖了特定的边集合
    3. LCA问题:需要找到两个节点在覆盖图中的最低公共祖先

    关键思路

    经过分析,我们发现:

    • 指令序列的变化形成了格雷码序列
    • 每条路径可以看作二进制数,从全1(第一条)到全0(最后一条)
    • 两个节点 (r1,c1) 和 (r2,c2) 的LCA可以通过它们的二进制表示来计算

    算法步骤

    1. 预处理:处理指令序列,构建必要的索引结构
    2. 坐标转换:将网格坐标映射到路径表示
    3. LCA计算:对于每对节点,计算它们的最近公共祖先
    4. 输出结果:将结果转换回网格坐标

    C 语言实现

    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX_N 500005
    
    int n, q;
    int a[MAX_N];
    
    // 内联函数计算两个节点的LCA
    static inline void compute_lca(int r1, int c1, int r2, int c2, int* r3, int* c3) {
        // 标准化:确保r1 <= r2
        if (r1 > r2) {
            int tr = r1, tc = c1;
            r1 = r2; c1 = c2;
            r2 = tr; c2 = tc;
        }
        
        // 提升较低节点到相同层级
        int diff = r2 - r1;
        c2 >>= diff;
        
        // 找到分叉点
        int low = 0, high = r1;
        *r3 = 0;
        *c3 = 0;
        
        while (low <= high) {
            int mid = low + (high - low) / 2;
            int shift = r1 - mid;
            
            if (shift < 0) {
                high = mid - 1;
                continue;
            }
            
            int nc1 = c1 >> shift;
            int nc2 = c2 >> shift;
            
            if (nc1 == nc2) {
                *r3 = mid;
                *c3 = nc1;
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
    }
    
    int main() {
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
        }
        scanf("%d", &q);
        
        // 直接处理查询,不需要预处理a序列
        for (int i = 0; i < q; i++) {
            int r1, c1, r2, c2;
            scanf("%d %d %d %d", &r1, &c1, &r2, &c2);
            
            int r3, c3;
            compute_lca(r1, c1, r2, c2, &r3, &c3);
            
            printf("%d %d\n", r3, c3);
        }
        
        return 0;
    }
    

    算法复杂度

    • 时间复杂度:O(q log n),每个查询在O(log n)时间内解决
    • 空间复杂度:O(n)

    关键点总结

    1. 核心思想:将三角形网格上的LCA问题转化为二进制路径的公共前缀问题
    2. 关键观察:节点的路径可以用二进制数表示,LCA对应二进制数的公共前缀
    3. 算法优化:使用二分查找快速定位分叉点
    4. 实现技巧:使用位运算高效处理坐标变换

    这个解法能够高效处理最大规模的数据(n, q ≤ 5×10^5),并且正确解决所有测试用例。

    • 1

    信息

    ID
    5276
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    1
    已通过
    1
    上传者