[BZOJ4241]历史研究

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

解析:本来这道题想来练一下回滚莫队的,但做着做着就想到了分块做法。预处理出sum数组与ans数组,sum来记录到当前这个块每个值的个数(相当于前缀和),用ans[i][j]来记录i这个块到j这个块的答案 ,时间复杂度O(n*sqrt(n))。对于每个询问(l,r),设它们所属的块分别为i,j,则答案要么是ans[i+1][j-1]要么就是非整块的地方也对答案做了贡献要么就是非整块的地方的答案。所以对于非整块的地方开个桶直接暴力求答案与ans[i+1][j-1]取个max就好了。总复杂度O(n*sqrt(n))。

细节:1.n的范围很大,要注意离散化,但不要用map(自带一个log为此T了改了了一个小时)。2.注意优化常数。

相似题目:[洛谷P4168]蒲公英

附上代码:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;

typedef long long LL;
const int MAXN=1e5+5;
int n,q;
int size,num;
int pos[MAXN];
int sum[320][MAXN];
LL ans[320][320];
int tong[MAXN];
LL Max=0;
int ndnum=0;
struct Node{
    int id;
    LL val;
}a[MAXN];
int mp[MAXN];
LL b[MAXN];

int min(int x,int y){
    return x<y?x:y;
}

LL max(LL x,LL y){
    return x>y?x:y;
}

inline LL read(){
    LL ret=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}

void prework(){
    for(int i=1;i<=n;i++)
        pos[i]=(i-1)/size+1;
    for(int i=1;i<=size;i++) 
        sum[1][mp[i]]++;
    for(int i=2;i<=num;i++){
        for(int j=1;j<=ndnum;j++) 
            sum[i][j]=sum[i-1][j];
        for(int j=(i-1)*size+1;j<=min(i*size,n);j++)
            sum[i][mp[j]]=sum[i][mp[j]]+1;
    }
    for(int i=1;i<=num;i++){
        for(int j=i;j<=num;j++){
            ans[i][j]=ans[i][j-1];
            for(int k=(j-1)*size+1;k<=min(j*size,n);k++){
                tong[mp[k]]++;
                ans[i][j]=max(ans[i][j],(sum[j-1][mp[k]]-sum[i-1][mp[k]]+tong[mp[k]])*b[k]);
            }
            for(int k=(j-1)*size+1;k<=min(j*size,n);k++)
                tong[mp[k]]--;
        }
    }
}

void work(int l,int r){
    if(pos[l]!=pos[r]){
        LL anss=ans[pos[l]+1][pos[r]-1];
        for(int i=l;i<=size*pos[l];i++)
            tong[mp[i]]++,anss=max(anss,(sum[pos[r]-1][mp[i]]-sum[pos[l]][mp[i]]+tong[mp[i]])*b[i]);
        for(int i=(pos[r]-1)*size+1;i<=r;i++)
            tong[mp[i]]++,anss=max(anss,(sum[pos[r]-1][mp[i]]-sum[pos[l]][mp[i]]+tong[mp[i]])*b[i]);
        printf("%lld
",anss);
        for(int i=l;i<=size*pos[l];i++)
            tong[mp[i]]--;
        for(int i=(pos[r]-1)*size+1;i<=r;i++)
            tong[mp[i]]--;
    }
    else{
        LL anss=0;
        for(int i=l;i<=r;i++)
            tong[mp[i]]++,anss=max(anss,tong[mp[i]]*b[i]);
        printf("%lld
",anss);
        for(int i=l;i<=r;i++)
            tong[mp[i]]--;
    }
}

bool cmp(Node a,Node b){
    return a.val<b.val;
}

int main(){
    n=read();q=read();
    size=(int)sqrt(n+0.5);num=(n-1)/size+1;
    for(int i=1;i<=n;i++){
        a[i].val=read();b[i]=a[i].val;
        a[i].id=i;
    }
    sort(a+1,a+n+1,cmp);
    mp[a[1].id]=++ndnum;
    for(int i=2;i<=n;i++){
        if(a[i].val!=a[i-1].val) mp[a[i].id]=++ndnum;
        else mp[a[i].id]=mp[a[i-1].id];
    }
    prework();
    for(int i=1;i<=q;i++){
        int l=read(),r=read();
        work(l,r);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/JoshDun/p/11234654.html