【JZOJ4763】【NOIP2016提高A组模拟9.7】旷野大计算 题目描述 输入 输出 样例输入 样例输出 数据范围 解法 代码 启发

【JZOJ4763】【NOIP2016提高A组模拟9.7】旷野大计算
题目描述
输入
输出
样例输入
样例输出
数据范围
解法
代码
启发

输入

【JZOJ4763】【NOIP2016提高A组模拟9.7】旷野大计算
题目描述
输入
输出
样例输入
样例输出
数据范围
解法
代码
启发

输出

【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

数据范围

【JZOJ4763】【NOIP2016提高A组模拟9.7】旷野大计算
题目描述
输入
输出
样例输入
样例输出
数据范围
解法
代码
启发

解法

离线莫队做法

考虑使用莫队,但由于在删数的时候难以处理,所以考虑“只增莫队”。
排序询问时以询问左端点所在块编号为第一关键字,右端点编号为第二关键字。
由于当左端点在同一个块时,移动最多为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;
}

启发

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