• BZOJ 4241: 历史研究——莫队 二叉堆


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4241

    题意:N个int范围内的数,M次询问一个区间最大的(数字*出现次数)(加权众数),可以离线。

    似乎正解是分块。。。因为可以离线&&时限大,用莫队算法卡常水过了(捂脸)。

    具体方法:先按莫队方法把询问排序,然后考虑转移。

    把所有数字离散化,记录每个数的(数字*出现次数),当我们加入/拿走一个数的时候,更新这个值,并维护二叉堆。

    复杂度:(O(N sqrt N log N))

    /**************************************************************
        Problem: 4241
        User: will7101
        Language: C++
        Result: Accepted
        Time:29968 ms
        Memory:5984 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN=100005;
    void rd(int &x){
        x=0; int ch=getchar();
        while(ch<'0'||'9'<ch) ch=getchar();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0', ch=getchar();
    }
    int N, M, V, S, be[MAXN], a[MAXN], id[MAXN], di[MAXN], num[MAXN];
    ll ans[MAXN], hp[MAXN];
    inline void add(int x){
        hp[id[x]]+=num[x];
        for(int i=id[x], j; i>1; i=j){
            j=i>>1;
            if(hp[i]>hp[j]){
                swap(hp[i], hp[j]);
                swap(id[di[i]], id[di[j]]);
                swap(di[i], di[j]);
            }else break;
        }
    }
    inline void del(int x){
        hp[id[x]]-=num[x];
        for(int i=id[x], j;; i=j){
            j=hp[i<<1]>hp[i<<1|1]?i<<1:i<<1|1;
            if(j>V) break;
            if(hp[i]<hp[j]){
                swap(hp[i], hp[j]);
                swap(id[di[i]], id[di[j]]);
                swap(di[i], di[j]);
            }else break;
        }
    }
    struct Qry{
        int l, r, id;
        bool operator<(const Qry &o)const{
            if(be[l]==be[o.l]) return (be[l]&1)?r>o.r:r<o.r;
            return l<o.l;
        }
    }Q[MAXN];
    void init(){
        sort(num+1, num+N+1); V=unique(num+1, num+N+1)-num-1;
        for(int i=1; i<=N; ++i) a[i]=lower_bound(num+1, num+V+1, a[i])-num;
        for(int i=1; i<=V; ++i) id[i]=di[i]=i;
    }
    int main(){
        rd(N), rd(M);
        for(int i=1; i<=N; ++i) rd(a[i]), num[i]=a[i];
        while(S*S<=M) S++;
        for(int i=0; i<=N; ++i) be[i]=i/S;
        init();
        for(int i=0; i<M; ++i) rd(Q[i].l), rd(Q[i].r), Q[i].id=i;
        sort(Q, Q+M);
        for(int i=0, l=1, r=0; i<M; ++i){
            while(r<Q[i].r) add(a[++r]);
            while(l>Q[i].l) add(a[--l]);
            while(l<Q[i].l) del(a[l++]);
            while(r>Q[i].r) del(a[r--]);
            ans[Q[i].id]=hp[1];
        }
        for(int i=0; i<M; ++i) printf("%lld
    ", ans[i]);
        return 0;
    }
    
  • 相关阅读:
    排球教练积分程序
    排球积分程序
    排球积分程序
    14周总结
    本周总结
    排球计分规则
    我与计算机
    排球计分程序
    《如何成为一个高手》观后感
    十八周总结
  • 原文地址:https://www.cnblogs.com/will7101/p/6605796.html
Copyright © 2020-2023  润新知