记录编号 617139 评测结果 AAAAAAWWWT
题目名称 1822.[AHOI 2013] 作业 最终得分 60
用户昵称 Gravatar2_16鸡扒拌面 是否通过 未通过
代码语言 C++ 运行时间 3.465 s
提交时间 2026-07-04 10:11:51 内存使用 8.91 MiB
显示代码纯文本
/*莫队算法为什么是神?在谈论这个问题之前,我想先说说其他数据结构算法相较于莫队究竟差在了哪里。
首先是犯下傲慢之罪的 ST 表,搞个 O(1) 查询算法名称就使用“神通”的词汇,这种傲慢的不支持修改算法注定走不长远。事实也是如此,在靠着时间复杂度赢了莫队之后一直在走下坡路,最终泯然众人。与之相比莫队就很谦卑,O(n23?),带修 O(n35?) 都是莫队留给稀疏表的慈悲,莫队不是不会 O(logn),只是不想通过太强悍的算法速度让稀疏表绝望所以故意不用。可笑有些人不理解莫队的良苦用心,竟然还用这些事讥讽莫队,我劝你们,耗子尾汁。
然后是犯下愤怒之罪的树状数组,因为一个点单点修改就找人家 logn 个祖宗谈话,区间问题有人提到莫队就怒气冲冲地炫耀时间复杂度的小常数,违背了莫队在 OI Wiki 中的一句话:“普通莫队是不能带修改的。”于是莫队降下了他的惩罚,树状数组悲惨失宠,在之后的区间问题中被线段树抢走职务,维护失败,一蹶不振。
接着是犯下懒惰之罪的线段树,自以为泛用就了不起了,自创区间打懒标记,另外大家有所不知,n 个数建立线段树,tr1? 闭上眼睛憧憬未来的时候,其脑海中看见的画面,正是站在区间查询之中的莫队,那时莫队告诉他:“你只可到这里,不可越过。”(指部分问题一般线段树不好处理)然而,莫队的劝说不但没有让线段树迷途知返,竟然还敢伙同愤怒的树状数组搞树套树,于是莫队降下了他的惩罚,吉司机线段树的下限变成了 log2n,时间复杂度惨遭毒瘤清算,从此从单 logn 算法之位坠落,永世不得翻身。
再然后是犯下了嫉妒之罪的回滚莫队,屡次被莫队击败,但口服心不服的回滚莫队暗中嫉妒着莫队,甚至胆敢当中说出如果没有普通莫队的话,大家都会回滚莫队了这种话。于是,在含金量最高的卡常大赛上,回滚莫队被莫队正面击溃。不过,念在回滚莫队最终怂了莫队的淫威,并且践行莫队的意志讨伐了屡次以下犯上的数据结构后,莫队应许了他在算法界的一切.
还有犯下贪婪之罪的主席树。只是算法的基础,主席树便拥有 n 个版本,而这,自然是因为莫队的应允。莫队允许主席树带线段树擅自出走,以 O(logn) 另立中央,只为让主席树代替自己争取更优的复杂度,甚至自己在复杂度“故意”输给 ST 表,将一切荣耀都归于他。但最后主席树却被胜利蒙蔽了双眼,也不再聆听莫队的教诲,甚至自以为荣光已经超过了莫队,竟允许自己的部下树套树自诩“他们才是好用的算法”,用这种算法亵渎莫队的尊严。于是莫队降下了惩罚,主席树此后在卡空间中被狂暴鸿儒,而线段树趁机背刺,树状数组带走了他的常数,各个版本提桶跑路,最后落得孤独终老的下场。
之后便是犯下暴食之罪的树套树。在主席树堕落之后,莫队开始寻找下一个代言人。这一次,他选中了树套树。相较于莫队,树套树无疑是不完美的。他没有莫队足以维护任何问题的合并,也没有足够的空间,甚至会导向出题人认定的坏算法。莫队认为或许是自己给主席树的压力过大,于是这一次莫队放任树套树开大空间,最终,树套树成功了。然而,完工后的树套树不但自诩“好用的算法”,更妄图染指莫队的威严,最终他也因此犯下了暴食之罪。空间开成了大卫带。
最后,犯下淫欲之罪的哈希表。耗尽了 O(n) 的时限后,莫队已经相当虚弱了。出题人用数据范围吸走了莫队的时间,莫队已经无力再惩罚年轻人。可此刻已经决心优化的莫队在最后依然心系数据结构的未来,于是他选中了第三位代言人――方便快速的哈希表。作为第三任代言人,哈希表很好的处理了区间问题,但在配合算法上,哈希表挡不住异端的诱惑,被 log 算法直接牛走,吸走了莫队赋予自己的时间复杂度,在最后站错了队,最后被莫队橄榄,彻底身败名裂。
至此,莫队终于将胆敢冒犯他的威严的算法斩杀殆尽,因此不出所料,在算法大赛的最终战,被单调队列以及单调栈踹上了 5×106 只脚,永世跑不完代码,可谓可喜可贺,万众欢呼。*/
#include<bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
using namespace std;

const int N = 1e5 + 10;
const int MQ = 1e6 + 10;
const int MB = 256; // 2^8
const int BUF_SIZE = 1 << 20;

// 缓冲区
char buf_in[BUF_SIZE], *p1 = buf_in, *p2 = buf_in;
char buf_out[BUF_SIZE], *p_out = buf_out;

inline char gc() {
    if(p1 == p2) {
        p2 = (p1 = buf_in) + fread(buf_in, 1, BUF_SIZE, stdin);
        if(p1 == p2) return EOF;
    }
    return *p1++;
}

inline int read() {
    int x = 0;
    char c = gc();
    while(c < '0' || c > '9') c = gc();
    while(c >= '0' && c <= '9') {
        x = x * 10 + (c ^ 48);
        c = gc();
    }
    return x;
}

inline void write(int x) {
    static char stk[12];
    register int top = 0;
    if(!x) *p_out++ = '0';
    else {
        while(x) {
            stk[++top] = (x % 10) ^ 48;
            x /= 10;
        }
        while(top) *p_out++ = stk[top--];
    }
}

int n, m, B;
int a[N];
int ql[MQ], qr[MQ], qa[MQ], qb[MQ], blk[MQ], order[MQ];
int ans1[MQ], ans2[MQ];

// 值域分块
int t, L[MB], R[MB], bl[N], s1[MB], s2[MB], cnt[N];

void build() {
    register int i;
    t = (100000 >> 8);
    for(i = 1; i <= t; i++) {
        L[i] = ((i - 1) << 8) + 1;
        R[i] = i << 8;
    }
    R[t] = 100000;
    for(i = 1; i <= 100000; i++)
        bl[i] = i >> 8;
}

inline void add(int x) {
    register int b = bl[x];
    if(!cnt[x]++) s1[b]++;
    s2[b]++;
}

inline void del(int x) {
    register int b = bl[x];
    --cnt[x];
    --s2[b];
    if(!cnt[x]) --s1[b];
}

inline int ask1(int l, int r) {
    register int p = bl[l], q = bl[r];
    register int ans = 0, i;
    if(p == q) {
        for(i = l; i <= r; ++i) ans += (cnt[i] > 0);
        return ans;
    }
    for(i = l; i <= R[p]; ++i) ans += (cnt[i] > 0);
    for(i = L[q]; i <= r; ++i) ans += (cnt[i] > 0);
    for(i = p + 1; i < q; ++i) ans += s1[i];
    return ans;
}

inline int ask2(int l, int r) {
    register int p = bl[l], q = bl[r];
    register int ans = 0, i;
    if(p == q) {
        for(i = l; i <= r; ++i) ans += cnt[i];
        return ans;
    }
    for(i = l; i <= R[p]; ++i) ans += cnt[i];
    for(i = L[q]; i <= r; ++i) ans += cnt[i];
    for(i = p + 1; i < q; ++i) ans += s2[i];
    return ans;
}

int main() {
    freopen("ahoi2013_homework.in", "r", stdin);
    freopen("ahoi2013_homework.out", "w", stdout);
    
    n = read(); m = read();
    B = max(1, (int)(n / sqrt(m) * 0.85));
    
    register int i;
    for(i = 1; i <= n; ++i) a[i] = read();
    for(i = 1; i <= m; ++i) {
        ql[i] = read(); qr[i] = read();
        qa[i] = read(); qb[i] = read();
        order[i] = i;
        blk[i] = ql[i] / B;
    }
    
    sort(order + 1, order + m + 1, [](int i, int j) {
        if(blk[i] != blk[j]) return blk[i] < blk[j];
        return (blk[i] & 1) ? (qr[i] < qr[j]) : (qr[i] > qr[j]);
    });
    
    build();
    
    register int l = 1, r = 0, idx;
    for(i = 1; i <= m; ++i) {
        idx = order[i];
        while(l > ql[idx]) add(a[--l]);
        while(r < qr[idx]) add(a[++r]);
        while(l < ql[idx]) del(a[l++]);
        while(r > qr[idx]) del(a[r--]);
        ans1[idx] = ask1(qa[idx], qb[idx]);
        ans2[idx] = ask2(qa[idx], qb[idx]);
    }
    
    for(i = 1; i <= m; ++i) {
        write(ans2[i]);
        *p_out++ = ' ';
        write(ans1[i]);
        *p_out++ = '\n';
    }
    
    fwrite(buf_out, 1, p_out - buf_out, stdout);
    return 0;
}