• BZOJ 4241: 历史研究 ( 回 滚 )


    题目:  链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4241

              题意:给你一个长度为n序列,m次查询,每次询问 一段区间 最大的  a[ i ] * cnt [ i ]  ( 重要度 * 出现次数)

    思路: 就是 一个块 一个块  的处理,对于 那些  l , r 在同一个块的查询 就 暴力 解决 ,对于那些  l 在同一个块 , r 不在 同一块的 查询咧, 它们的 r 是从小到大排的,那么这里的 r 至少在下一块,因为在这一块的都暴力解决了,那么就搞两个指针 l , r ,  l 指向块尾加1,因为 l 可以刚好在块尾,so,要加1,然后 r 指向快尾,因为 r 至少下下一块嘛, 那就 先 r 向右直到到达 q [ i ] . r ,然后再 l,向左到 q [ i ] . l  ,记录完答案后列, l 指针就 滚回 块尾+1,把影响消除就行了   (  这里采用的方法 是  另一个数 P 等于 l 还没向左移动的时候的 ans 值 (代码中是tmp) , 然后移动 l  ,跟新ans,  然后记录完答案 就 把 l  滚回 块尾+1, 然后重新让 ans = p ,  那就等于 l 没动过嘛 )

    #include<bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define rep(i,j,k) for(int i=j;i<=k;i++)
    #define dep(i,j,k) for(int i=k;i>=j;i--)
    #define INF 0x3f3f3f3f
    #define mem(i,j) memset(i,0,sizeof(i))
    #define make(i,j) make_pair(i,j)
    #define pb push_back
    using namespace std;
    const int N=1e5+111;
    int a[N],b[N],c[N],cnt[N],pos[N],n,m,block;
    LL tmp,ans[N];
    struct noq {
        int l,r,id;
    }q[N];
    bool cmp(noq a,noq b) {
        return pos[a.l]==pos[b.l]?a.r<b.r:pos[a.l]<pos[b.l];
    }
    LL query(int l,int r) { ///暴力求答案
        int t[N]; rep(i,l,r) t[b[i]]=0; LL ret=0;
        rep(i,l,r) ++t[b[i]],ret=max(ret,1LL*t[b[i]]*a[i]);
        return ret;
    }
    void add(int x) {
        ++cnt[b[x]];
        tmp=max(tmp,1LL*cnt[b[x]]*a[x]);
    }
    int slove(int qnum,int bnum) { ///处理 第 bnum 块, 现在 处理到 q[qnum] 这个查询
        int i=qnum; int L=min(bnum*block,n); int l=L+1,r=L; tmp=0; ///L 即为块尾
        rep(j,1,n) cnt[j]=0; ///初始化,每处理一个块 都要 搞一次的啦
        for(;pos[q[i].l]==bnum;i++) {
            if(pos[q[i].l]==pos[q[i].r]) {/// l,r 在同一块,暴力处理
                ans[q[i].id]=query(q[i].l,q[i].r); continue;
            }
            while(r<q[i].r) add(++r); ///先移动 r 指针
            LL p=tmp; ///记录 l 指针 移动前的 tmp 值
            while(l>q[i].l) add(--l);
            ans[q[i].id]=tmp; ///记录答案
            tmp=p; ///还原 tmp
            while(l<L+1) --cnt[b[l++]]; /// l 滚回块尾+1
        }
        return i; ///处理完这一块后,处理到第i个查询
    }
    int main() {
        scanf("%d %d",&n,&m);
        block=sqrt(n);
        rep(i,1,n) {
            scanf("%d",&a[i]); c[i]=a[i]; pos[i]=(i-1)/block+1;///一定要加1喔,因为slove的时候l,r初始化需要
        }
        int up=pos[n]; ///块数
        sort(c+1,c+1+n);
        int newn=unique(c+1,c+1+n)-(c+1);
        rep(i,1,n) {
            b[i]=lower_bound(c+1,c+1+newn,a[i])-c;///数据太大,离散化a[i]
        }
        rep(i,1,m) {
            scanf("%d %d",&q[i].l,&q[i].r); q[i].id=i;
        }
        sort(q+1,q+1+m,cmp);
        int pp=1; ///处理到的 q[i],pp即为i;
        rep(i,1,up) {
            pp=slove(pp,i);
        }
        rep(i,1,m) printf("%lld
    ",ans[i]);
        return 0;
    }
    View Code

    回滚 莫队 的 时间 复杂度 是 n * sqrt( n ) ;

    一步一步,永不停息
  • 相关阅读:
    hdu--1018--Big Number(斯特林公式)
    NYOJ--56--阶乘因式分解(一)
    hdu--1711--kmp应用在整形数组--Number Sequence
    HDU--1358--KMP算法失配函数getfail()的理解--Period
    C++STL(vector,map,set,list,bitset,deque)成员函数整理
    NYOJ--95--multiset--众数问题
    NYOJ--86--set.find()--找球号(一)
    NYOJ--19--next_permutation()--擅长排列的小明
    NYOJ--714--Card Trick
    NYOJ--2--括号配对问题
  • 原文地址:https://www.cnblogs.com/Willems/p/10891152.html
Copyright © 2020-2023  润新知