【JZOJ4763】【NOIP2016提高A组模拟9.7】旷野大计算

题目描述

这里写图片描述

输入

这里写图片描述

输出

这里写图片描述

样例输入

5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4

样例输出

9
8
8
16
16

数据范围

这里写图片描述

解法

离线莫队做法

考虑使用莫队,但由于在删数的时候难以处理,所以考虑“只增莫队”。
排序询问时以询问左端点所在块编号为第一关键字,右端点编号为第二关键字。
由于当左端点在同一个块时,移动最多为n^0.5,所以每次询问把左端点直接从块末移动到目标位置,这样就只增不减了。

在线分块做法

坑待填

代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define ll long long
using namespace std;
const char* fin="aP3.in";
const char* fout="aP3y.out";
const int inf=0x7fffffff;
ll read(){
    char ch=getchar();
    ll x=0;
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
const ll maxn=100007,maxt=maxn*4;
struct node{
    ll v,id;
}a[maxn];
struct qj{
    ll l,r,lk,rk,id;
}q[maxn];
ll n,m,i,j,k,ks,l,r,tmp,tmd,tmb;
ll b[maxn],c[maxn],tong[maxn],la[maxn];
ll ans1[maxn];
bool cmp(node a,node b){
    return a.v<b.v;
}
bool cmp1(qj a,qj b){
    return a.lk<b.lk || a.lk==b.lk && a.r<b.r;
}
ll pos(ll v){
    return (v-1)/ks+1;
}
void add(ll v){
    tmb=max(tmb,(++tong[c[v]]+la[c[v]])*b[v]);
}
int main(){
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++) scanf("%d",&b[i]),a[i].v=b[i],a[i].id=i;
    sort(a+1,a+n+1,cmp);
    j=0;
    ks=int(sqrt(n));
    for (i=1;i<=n;i++) {
        if (a[i].v>a[i-1].v) j++;
        c[a[i].id]=j;
    }
    for (i=1;i<=m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].lk=pos(q[i].l);
        q[i].rk=pos(q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp1);
    l=0;
    r=0;
    tmp=0;
    for (i=1;i<=m;i++){
        if (q[i-1].lk!=q[i].lk){
            memset(la,0,sizeof(la));
            tmd=q[i].lk*ks;
            r=tmd+1;
            tmp=tmb=0;
        }
        l=min(q[i].r+1,tmd+1);
        /*while (l<q[i].l) del(l++);
        while (r>q[i].r) del(r--);*/
        while (l>q[i].l) add(--l);
        while (r<=q[i].r) {
            tmp=max(tmp,(++la[c[r]])*b[r]);
            tmb=max(tmb,(tong[c[r]]+la[c[r]])*b[r]);
            r++;
        }
        for (j=l;j<=q[i].r && j<=tmd;j++) tong[c[j]]--;
        ans1[q[i].id]=tmb;
        tmb=tmp;
    }
    for (i=1;i<=m;i++) printf("%lld
",ans1[i]);
    return 0;
}

启发

当莫队删数困难时,考虑“只增莫队”。

原文地址:https://www.cnblogs.com/hiweibolu/p/6714902.html