9b44905c4fd463afcfee852d9467d03

#define ll long long  // 定义long long为ll,简化代码书写
using namespace std;
// 线段树类:用于维护元素频率,支持更新、第k小查询和区间和查询
struct SegTree{
    int m;  // 离散化后的值域大小(不同元素的数量)
    vector<int>tree_sum;  // 线段树节点数组,存储区间内元素的总频率

    // 构造函数:初始化线段树大小
    SegTree(int size){
        m = size;  // 记录离散化后的值域大小
        // 线段树数组大小开4倍,确保能容纳所有节点(避免越界)
        tree_sum.assign(4 * size, 0);
    }

    // 递归实现单点更新:更新指定位置的频率(delta为+1或-1)
    // id:当前节点编号;l/r:当前节点覆盖的区间;pos:要更新的位置;delta:变化量
    void update(int id, int l, int r, int pos, int delta){
        if(l == r){  // 到达叶子节点(对应单个离散化后的值)
            tree_sum[id] += delta;  // 更新频率
            return;
        }
        int mid = (l + r) / 2;  // 划分左右子区间
        if(pos <= mid){  // 目标位置在左子区间,递归更新左子树
            update(id << 1, l, mid, pos, delta);  // id<<1等价于2*id(左子节点编号)
        } else {  // 目标位置在右子区间,递归更新右子树
            update(id << 1 | 1, mid + 1, r, pos, delta);  // id<<1|1等价于2*id+1(右子节点编号)
        }
        // 回溯时更新当前节点的总频率(左右子树频率之和)
        tree_sum[id] = tree_sum[id << 1] + tree_sum[id << 1 | 1];
    }

    // 对外接口:简化更新调用(从根节点开始)
    void update(int pos, int delta){
        update(1, 0, m - 1, pos, delta);  // 根节点编号为1,覆盖区间[0, m-1]
    }

    // 递归实现第k小查询:返回第k小元素的离散化索引
    // id:当前节点编号;l/r:当前节点覆盖的区间;k:目标第k小(0-based)
    int kth(int id, int l, int r, int k){
        if(l == r){  // 到达叶子节点,返回当前位置(即第k小元素的索引)
            return l;
        }
        int mid = (l + r) / 2;  // 划分左右子区间
        // 左子树的频率总和为tree_sum[id<<1]
        if(k < tree_sum[id << 1]){  // 第k小在左子树
            return kth(id << 1, l, mid, k);
        } else {  // 第k小在右子树,减去左子树的频率后查询
            return kth(id << 1 | 1, mid + 1, r, k - tree_sum[id << 1]);
        }
    }

    // 对外接口:简化第k小查询调用(从根节点开始)
    int kth(int k){
        return kth(1, 0, m - 1, k);
    }

    // 递归实现区间和查询:返回[ql, qr]区间内的频率总和
    // id:当前节点编号;l/r:当前节点覆盖的区间;ql/qr:查询区间
    int query_sum(int id, int l, int r, int ql, int qr){
        if(ql > qr) return 0;  // 查询区间无效,返回0
        if(ql <= l && r <= qr){  // 当前节点区间完全被查询区间包含
            return tree_sum[id];  // 直接返回当前节点的总频率
        }
        int mid = (l + r) / 2;  // 划分左右子区间
        int res = 0;  // 存储查询结果
        if(ql <= mid){  // 左子区间与查询区间有交集,递归查询左子树
            res += query_sum(id << 1, l, mid, ql, qr);
        }
        if(qr > mid){  // 右子区间与查询区间有交集,递归查询右子树
            res += query_sum(id << 1 | 1, mid + 1, r, ql, qr);
        }
        return res;  // 返回左右子树的频率总和
    }

    // 对外接口:简化区间和查询调用(从根节点开始)
    int query_sum(int ql, int qr){
        return query_sum(1, 0, m - 1, ql, qr);
    }
};

int main(){
    ios::sync_with_stdio(false);  // 关闭输入输出同步,加速cin/cout
    cin.tie(0);

    int t;  // 测试用例数量
    cin >> t;
    while(t--){  // 循环处理每个测试用例
        int n, q;  // n:初始数组长度;q:操作次数
        cin >> n >> q;
        vector<ll>a(n);  // 存储初始数组元素
        for(int i = 0; i < n; i++){
            cin >> a[i];
        }

        // 收集所有可能出现的值(初始值+所有更新后的值),用于离散化
        vector<pair<int, ll>>ops;  // 存储所有操作(位置p和增量v)
        vector<ll>all = a;  // 初始值加入待离散化列表
        vector<ll>cur = a;  // 模拟数组更新过程,用于收集更新后的值

        // 读取所有操作,收集更新后的值
        for(int i = 0; i < q; i++){
            int p; ll v;  // p:位置(1-based);v:增量
            cin >> p >> v;
            p--;  // 转换为0-based索引
            ops.push_back({p, v});  // 记录操作
            cur[p] += v;  // 模拟更新当前位置的值
            all.push_back(cur[p]);  // 将更新后的值加入待离散化列表
        }

        // 离散化处理:排序+去重
        sort(all.begin(), all.end());  // 排序所有可能的值
        // 去重:删除连续重复元素,保留唯一值
        all.erase(unique(all.begin(), all.end()), all.end());
        int m = all.size();  // 离散化后的值域大小(不同值的数量)

        // 初始化线段树,大小为m
        SegTree segtree(m);

        vector<ll>cur_val = a;  // 当前数组的值(初始为a)
        vector<int>idx(n);  // 存储每个元素对应的离散化索引

        // 初始化线段树:将初始元素插入线段树
        for(int i = 0; i < n; i++){
            // 查找当前元素在离散化列表中的索引(lower_bound返回第一个>=目标值的位置)
            idx[i] = lower_bound(all.begin(), all.end(), cur_val[i]) - all.begin();
            segtree.update(idx[i], 1);  // 插入元素(频率+1)
        }

        vector<int>ans_list;  // 存储每次查询的结果

        // 处理每个操作
        for(int i = 0; i < q; i++){
            int p = ops[i].first;  // 操作位置(0-based)
            ll v = ops[i].second;  // 增量

            ll old_val = cur_val[p];  // 原数值
            ll new_val = old_val + v;  // 更新后的新数值
            cur_val[p] = new_val;  // 更新当前数组的值

            // 计算原数值和新数值的离散化索引
            int old_idx = idx[p];  // 原索引
            // 新索引:查找新值在离散化列表中的位置
            int new_idx = lower_bound(all.begin(), all.end(), new_val) - all.begin();
            idx[p] = new_idx;  // 更新索引记录

            // 更新线段树:删除原数值(频率-1),插入新数值(频率+1)
            segtree.update(old_idx, -1);
            segtree.update(new_idx, 1);

            // 计算阈值t:n - (n/2)(例如n=5时t=3,对应第3小元素)
            int threshold = n - (n / 2);
            // 查询第threshold小元素的离散化索引(注意:kth是0-based,threshold需减1)
            int x_idx = segtree.kth(threshold - 1);

            // 计算小于x_idx的元素总数(即[0, x_idx-1]区间的频率和)
            int ans = 0;
            if(x_idx > 0){  // 若x_idx>0,查询有效区间
                ans = segtree.query_sum(0, x_idx - 1);
            }
            ans_list.push_back(ans);  // 记录结果
        }

        // 输出所有查询结果
        for(int i = 0; i < q; i++){
            cout << ans_list[i] << '\n';
        }
    }

    return 0;
}`

**注意这个题目中的数会修改,我们存下问题离线进行,将每一个修改后的可能值都存入all中,然后再离散化**