P2709 小B的询问 查询莫队

解题思路

本题需要使用莫队算法来高效处理多个区间查询。题目要求计算每个查询区间内所有数字出现次数的平方和。具体步骤如下:

  1. 莫队算法框架:将查询分块排序,通过移动区间指针来高效处理多个查询

  2. 平方和维护:动态维护当前区间内各数字出现次数的平方和

  3. 指针移动处理:在移动区间指针时,实时更新平方和

  4. 值域过滤:只统计值域在[1,k]范围内的数字

代码注释

#include<bits/stdc++.h>
#define ll long long  // 定义long long为ll,方便使用
using namespace std;
const int N = 1e5 + 10;  // 定义最大数据范围

// 查询结构体:存储每个查询的左右端点和查询编号
struct node {
    int l, r, id;
};
node t[N];  // 存储所有查询

// 变量定义
int n, m, k, bcnt, a[N], cnt[N];  // n序列长度,m查询数,k值域上限,bcnt块大小,a序列,cnt计数数组
ll sum, ans[N];  // sum当前平方和,ans存储每个查询的答案
int L = 1, R;    // 当前区间指针[L,R]

// 查询排序比较函数
bool cmp(node a, node b) {
    // 按块排序,同一块内按右端点排序
    if(a.l / bcnt == b.l / bcnt) return a.r < b.r;
    else return a.l < b.l;
}

// 从当前区间移除位置pos的数字
void del(int pos) {
    if(a[pos] <= k) {  // 只处理值域范围内的数字
        sum -= (ll)cnt[a[pos]] * cnt[a[pos]];  // 先减去旧的平方值
        cnt[a[pos]]--;                         // 减少计数
        sum += (ll)cnt[a[pos]] * cnt[a[pos]];  // 加上新的平方值
    } else {
        cnt[a[pos]]--;  // 超出值域的数字只更新计数
    }
}

// 添加位置pos的数字到当前区间
void add(int pos) {
    if(a[pos] <= k) {  // 只处理值域范围内的数字
        sum -= (ll)cnt[a[pos]] * cnt[a[pos]];  // 先减去旧的平方值
        cnt[a[pos]]++;                         // 增加计数
        sum += (ll)cnt[a[pos]] * cnt[a[pos]];  // 加上新的平方值
    } else {
        cnt[a[pos]]++;  // 超出值域的数字只更新计数
    }
}

int main() {
    // 输入数据
    scanf("%d%d%d", &n, &m, &k);
    bcnt = sqrt(n);  // 计算块大小
    
    // 输入序列
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    
    // 输入查询
    for(int i = 1; i <= m; i++) {
        scanf("%d%d", &t[i].l, &t[i].r);
        t[i].id = i;  // 记录查询编号
    }
    
    // 对查询进行排序
    sort(t + 1, t + 1 + m, cmp);
    
    // 处理每个查询
    for(int i = 1; i <= m; i++) {
        int tl = t[i].l, tr = t[i].r, tid = t[i].id;
        
        // 调整区间指针L
        while(L < tl) del(L++);  // 左指针右移,删除左边元素
        while(L > tl) add(--L);  // 左指针左移,添加左边元素
        
        // 调整区间指针R
        while(R < tr) add(++R);  // 右指针右移,添加右边元素
        while(R > tr) del(R--);  // 右指针左移,删除右边元素
        
        // 存储当前查询的答案
        ans[tid] = sum;
    }
    
    // 输出结果
    for(int i = 1; i <= m; i++)
        printf("%lld\n", ans[i]);
    
    return 0;
}

 

posted @ 2025-06-22 11:23  CRt0729  阅读(11)  评论(0)    收藏  举报