基础认知
一、二叉树种类:
1.满二叉树。记深度k,节点数量2^k-1。
2.完全二叉树:除了底层,其余全满,底部从左到右连续。
3,平衡二叉搜索树:左子树和右子树高度差不大于1。
二、存储方式:
顺序存储:已知代码i的元素,其左右“孩子”代码为2i和2i+1。
三、遍历方式:
1.深度优先搜索(前中后序遍历)【递归】【迭代】
前:中左右;中:左中右;后:左右中。
2.广度优先遍历(层序遍历)【迭代】
奇点杯试题分析
1.高效求和判断完全平方数
 
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
// 计算满足条件的数对数量
ll count_pairs(ll n) {
    ll total = 0; // 用于存储结果
    const ll s_limit = 2 * n; // 两个数的最大和
    ll k_max = static_cast<ll>(sqrt(s_limit)); // 最大可能的平方根
    // 确保 k_max 是最大的满足 k_max^2 <= s_limit 的整数
    while ((k_max + 1) * (k_max + 1) <= s_limit) ++k_max;
    // 遍历所有可能的完全平方数
    for (ll k = 2; k <= k_max; ++k) {
        const ll s = k * k; // 当前完全平方数
        const ll a = max(1LL, s - n); // i 的最小值
        const ll b = (s - 1) / 2; // i 的最大值
        if (a <= b) {
            total += b - a + 1; // 累加满足条件的数对数量
        }
    }
    return total;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll n;
    cin >> n; // 输入 n
    cout << count_pairs(n) << "\n"; // 输出结果
    return 0;
}难点:使用暴力法会TLE.不能使用多重循环。
2.计算连续子数组元素之和

#include <iostream>
using namespace std;
typedef long long ll;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll n;
    cin >> n; // 输入数组长度
    ll total = 0; // 用于存储最终结果
    for (ll i = 1; i <= n; ++i) {
        ll x;
        cin >> x; // 逐个输入数组元素
        total += x * i * (n - i + 1); // 计算当前元素的贡献并累加
    }
    cout << total << "\n"; // 输出结果
    return 0;
}难点:不能直接使用数组存放元素,会造成段错误。
3. DSU算法

#include<bits/stdc++.h>
using namespace std;
int n, m, k;
int fa[100005]; // 并查集数组
// 查找函数,带路径压缩
int find(int x) {
    if (fa[x] == x) return fa[x]; // 如果 x 是自己的父节点,直接返回
    else return fa[x] = find(fa[x]); // 否则递归查找,并压缩路径
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
    cin >> T; // 读取测试数据组数
    while (T--) {
        cin >> n >> m; // 读取节点数 n 和边数 m
        // 初始化并查集
        for (int i = 1; i <= n; ++i)
            fa[i] = i;
        // 读取 m 条边并合并集合
        for (int i = 1; i <= m; ++i) {
            int x, y;
            cin >> x >> y;
            int xx = find(x), yy = find(y); // 查找 x 和 y 的根节点
            if (xx == yy) continue; // 如果已经在同一个集合,跳过
            fa[xx] = yy; // 合并集合
        }
        cin >> k; // 读取查询数 k
        int st;
        cin >> st; // 读取起始节点 st
        st = find(st); // 查找 st 的根节点
        bool flag = 1; // 标志位,表示所有查询节点是否与 st 在同一个集合
        // 检查接下来的 k-1 个节点
        for (int i = 2; i <= k; ++i) {
            int ed;
            cin >> ed; // 读取查询节点
            ed = find(ed); // 查找 ed 的根节点
            flag &= (st == ed); // 检查是否与 st 在同一个集合
        }
        // 输出结果
        puts(flag ? "YES" : "NO");
    }
    return 0;
}4.计算因子并统计次数

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
const int MAX_A = 2e5 + 10;
vector<int> get_factors(int v) {
    vector<int> res;
    for (int i = 1; i * i <= v; ++i) {
        if (v % i == 0) {
            res.push_back(i);
            if (i != v / i) {
                res.push_back(v / i);
            }
        }
    }
    return res;
}
int cnt[MAX_A];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    long long ans = 0;
    for (int v : a) {
        auto factors = get_factors(v);
        long long sum = 0;
        for (int x : factors) {
            sum += cnt[x];
        }
        sum %= MOD;
        ans = (ans + sum) % MOD;
        cnt[v] = (cnt[v] + 1) % MOD; // 只增加当前元素的计数
    }
    cout << ans << endl;
    return 0;
}


















