• 莫队算法


    http://www.cnblogs.com/hzf-sbit/p/4056874.html

    https://www.zhihu.com/question/27316467/answer/36260465

    处理一类无修改的离线区间询问问题

    复杂度为O(n*sqrt(n)*a),a为单次更新操作的复杂度。

    hihocoder1488

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 2e4+20;
    int a[N];
    
    long long ans[N], now;
    
    struct Q{
        int l, r, p;
    }q[N];
    
    int c_num[N], c_time[N];
    pair<long long, long long> sum(int x) {
        long long num = 0, time = 0;
        while(x) {
            num += c_num[x];
            time += c_time[x];
            x -= x&-x;
        }
        return {num, time};
    }
    void add(int x, int d) {
        for(int i = x; i < N; i += i&-i) {
            c_num[i] += d;
            c_time[i] += d > 0? x: -x;
        }
    }
    
    void add(int x) {
        x = a[x];
        auto u = sum(x), v = sum(N-1);
        now += (v.first-u.first)*x+u.second+x;
        add(x, 1);
    }
    void del(int x) {
        x = a[x];
        add(x, -1);
        auto u = sum(x), v = sum(N-1);
        now -= (v.first-u.first)*x+u.second+x;
    }
    
    int main() {
        int t; scanf("%d", &t);
        while(t--) {
            memset(c_num, 0, sizeof(c_num));
            memset(c_time, 0, sizeof(c_time));
            now = 0;
    
            int n, m;
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i++)
                scanf("%d", a+i);
    
            /*莫队算法*/
            int lim = sqrt(n+0.5);
            for(int l, r, i = 1; i <= m; i++) {
                scanf("%d%d", &l, &r);
                q[i] = Q{l, r, i};
            }
            sort(q+1, q+m+1, [&](Q a, Q b){ return a.l/lim == b.l/lim? a.r < b.r : a.l/lim < b.l/lim; });
    
            for(int i = 1, l = 1, r = 0; i <= m; i++) {
                int L = q[i].l, R = q[i].r;
                while(l < L) del(l++);
                while(l > L) add(--l);
                while(r < R) add(++r);
                while(r > R) del(r--);
                ans[ q[i].p ] = now;
             }
             for(int i = 1; i <= m; i++)
                printf("%lld
    ", ans[i]);
        }
        return 0;
    }
    作者:张瑯小强
    链接:https://www.zhihu.com/question/27316467/answer/130423804
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    *********************************
    问题:有n个数组成一个序列,有m个形如询问L, R的询问,每次询问需要回答区间内至少出现2次的数有哪些。
    *********************************
    
    int len;    // 块长度
    struct Query{
        int L, R, ID, block;
        Query(){}  // 构造函数重载
        Query(int l, int r, int ID):L(l), R(r), ID(ID){
            block = l / len;
        }
        bool operator < (const Query rhs) const {
            if(block == rhs.block) return R < rhs.R;  // 不是if(L == rhs.L) return R < rhs.R; return L < rhs.L
            return block < rhs.block;           // 否则这就变回算法一了
        }
    }queries[maxm];
    
    map<int, int> buf;
    
    inline void insert(int n){
        if(buf.count(n))
            ++buf[n];
        else
            buf[n] = 1;
    }
    inline void erase(int n){
        if(--buf[n] == 0) buf.erase(n);
    }
    
    int A[maxn];        // 原序列
    queue<int> anss[maxm];  // 存储答案
    
    int main(){
        int n, m;
        cin >> n;
        len = (int)sqrt(n);    // 块长度
        for(int i = 1; i <= n; i++){
            cin >> A[i];
        }
        cin >> m;
        for(int i = 1; i <= m; i++){
            int l, r;
            cin >> l >> r;
            queries[i] = Query(l, r, i);
        }
        sort(queries + 1, queries + m + 1);
        int L = 1, R = 1;
        buf[A[1]] = 1;
        for(int i = 1; i <= m; i++){
            queue<int>& ans = anss[queries[i].ID];
            Query &qi = queries[i];
            while(R < qi.R) insert(A[++R]);
            while(L > qi.L) insert(A[--L]);
            while(R > qi.R) erase(A[R--]);
            while(L < qi.L) erase(A[L++]);
    
            for(map<int, int>::iterator it = buf.begin(); it != buf.end(); ++it){
                if(it->second >= 2){
                    ans.push(it->first);
                }
            }
        }
        for(int i = 1; i <= m; i++){
            queue<int>& ans = anss[i];
            while(!ans.empty()){
                cout << ans.front() << ' ';
                ans.pop();
            }
            cout << endl;
        }
    }

    在update的同时更新ans。(本题可考虑维护一个set,表示出现至少两次的数的集合)

  • 相关阅读:
    大数据存储技术_磁盘与阵列技术
    OpenMP Programming
    大数据存储技术_背景
    群ping
    Markdown使用说明
    随笔记录--清楚sqlserver r2 的连接记录
    ORACLE备份保留策略CONFIGURE RETENTION POLICY
    ORA-00257:archiver error.Connect internal only, until freed
    expdp数据泵导出日志信息不全的问题
    处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错误模块“ManagedPipelineHandler”
  • 原文地址:https://www.cnblogs.com/dirge/p/7222875.html
Copyright © 2020-2023  润新知