动态线段树开点为什么会 WA和 RE
查看原帖
动态线段树开点为什么会 WA和 RE
678217
kingradshj楼主2025/1/27 14:42
#include<iostream>
#define int long long
using namespace std;
const int N = 5e5 + 10;

// 定义线段树结构体
struct seg_tree{
    int tot; // 动态建树时的节点编号计数器
    // 定义线段树的节点结构体
    struct node{
        int l,r; // 该节点所代表区间的左右端点  
        int sum; // 该节点所代表区间的和
        int s[2]; // s[0] 存储左子节点编号,s[1] 存储右子节点编号
    }p[N<<2]; // 存储线段树节点的数组,N<<2 相当于 4*N

    // 向上更新节点信息,根据左右子节点的和更新当前节点的和
    void push_up(int now){
        p[now].sum = p[p[now].s[0]].sum + p[p[now].s[1]].sum;
    }

    // 初始化线段树,调用 build 函数构建线段树
    void init(int n){
        build(1,n);
    }

    // 构建线段树,返回当前节点的编号
    int build(int l,int r){
        tot++; // 节点编号加 1
        p[tot].l = l; // 设置当前节点的左端点
        p[tot].r = r; // 设置当前节点的右端点
        return tot; // 返回当前节点的编号
    }

    // 单点修改操作,将位置 pos 的值增加 u
    void add(int now,int pos,int u){ 
        int l = p[now].l,r = p[now].r; // 获取当前节点的左右端点
        int mid = (l+r) >> 1; // 计算区间中点

        // 如果当前节点没有左右子节点,构建左右子节点
        if(!p[now].s[0]){
            p[now].s[0] = build(p[now].l,mid);
            p[now].s[1] = build(mid+1,p[now].r);
        } 

        // 如果当前节点是叶子节点,更新该节点的和
        if(l == r){
            p[now].sum += u;
            return ;
        }

        // 根据 pos 与 mid 的大小关系,递归修改左子树或右子树
        if(mid >= pos) add(p[now].s[0],pos,u); 
        else add(p[now].s[1],pos,u);

        // 向上更新节点信息
        push_up(now);
    }

    // 区间查询操作,查询区间 [tl, tr] 的和
    int ask(int now,int tl,int tr){
        int sum = 0; // 用于存储查询结果
        int l = p[now].l,r = p[now].r; // 获取当前节点的左右端点
        int mid = (l+r) >> 1; // 计算区间中点

        // 如果当前节点没有左右子节点,构建左右子节点
        if(!p[now].s[0]){
            p[now].s[0] = build(p[now].l,mid);
            p[now].s[1] = build(mid+1,p[now].r);
        } 

        // 如果当前节点的区间完全包含在查询区间内,返回该节点的和
        if(tl <= l && r <= tr) return p[now].sum; 

        // 根据查询区间与 mid 的关系,递归查询左子树和右子树
        if(mid >= tl) sum += ask(p[now].s[0],tl,tr);
        if(mid < tr) sum += ask(p[now].s[1],tl,tr);

        return sum; // 返回查询结果
    }
}T;

int n,ans=0; // n 表示数组长度,ans 用于存储逆序对的数量
int a[N]; // 存储输入的数组

signed main(){
    // 关闭输入输出流的同步,提高输入输出效率
    ios::sync_with_stdio(false);
    cin >> n; // 输入数组的长度
    T.init(1e9); // 初始化线段树,区间范围为 [1, 1e9]

    // 循环读取数组元素
    for(int i=1;i<=n;++i){
        cin >> a[i]; // 输入数组的第 i 个元素
        // 查询区间 [a[i], n] 的和,并累加到 ans 中
        ans += T.ask(1,a[i],n); 
        // 将位置 a[i] 的值加 1
        T.add(1,a[i],1); 
    }

    cout << ans; // 输出逆序对的数量
    return 0;
}
2025/1/27 14:42
加载中...