4540: [Hnoi2016]序列|莫队+ST表

考虑现在已经知道了[l,r]的答案新添入一个r+1如何更新答案

也就是右端点在r+1处左端点在l..r+1之间的所有的子序列的答案

可以找出l..r中最小的数的位置p,然后p以及p左侧作为左端点的答案就可以直接计算了

考虑左端点在p+1....r+1时对答案的贡献,可以与处理一个前缀和Si表示以i为右端点的所有子序列的答案之和

那么左端点在p+1....r+1时对答案的贡献就是Sr+1?Sp

其他端点移动的做法也同理

为什么我的莫队跑了17s,而网上的其他莫队只需要5s,人傻自带三倍常数QWQ

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<ctime>
#include<set>
#include<map>
#define N 110000
#define ll long long
using namespace std;
int sc()
{
    int i=0,f=1; char c=getchar();
    while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘)i=i*10+c-‘0‘,c=getchar();
    return i*f;
}
struct W{int l,r,p;} b[N];
long long sl[N],sr[N],ans[N],now;
int bl[N],l[N],r[N],a[N],st[N][17],q[N];
int n,Q,block;
void pre()
{
    for(int i=1;i<=n;i++) st[i][0]=i;
    for(int k=1;(1<<k)<=n;k++)
        for(int i=1;i<=n;i++)
            if(i+(1<<k)>n+1)break;
            else if(a[st[i][k-1]]<a[st[i+(1<<k-1)][k-1]]) st[i][k]=st[i][k-1];
            else st[i][k]=st[i+(1<<k-1)][k-1];
    int qr=0;
    for(int i=1;i<=n;i++)
    {
        while(qr&&a[q[qr]]>=a[i])qr--;
        l[i]=q[qr]; q[++qr]=i;
        sl[i]=sl[l[i]]+1ll*a[i]*(i-l[i]);
    }
    q[qr=0]=n+1;
    for(int i=n;i>=1;i--)
    {
        while(qr&&a[q[qr]]>a[i])qr--;
        r[i]=q[qr]; q[++qr]=i;
        sr[i]=sr[r[i]]+1ll*a[i]*(r[i]-i);
    }
}
bool cmp(W a,W b)
{
    return bl[a.l]<bl[b.l]||(bl[a.l]==bl[b.l]&&a.r<b.r);
}
int get_min(int l,int r)
{
    int k=log2(r-l+1);
    int L=st[l][k],R=st[r-(1<<k)+1][k];
    return a[L]<a[R]?L:R;
}
long long call(int l,int r)
{
    int p=get_min(l,r);
    return 1ll*(r-p+1)*a[p]+sr[l]-sr[p];
}
long long calr(int l,int r)
{
    int p=get_min(l,r);
    return 1ll*(p-l+1)*a[p]+sl[r]-sl[p];
}
int main()
{
    n=sc(),Q=sc();block=sqrt(n);
    for(int i=1;i<=n;i++)
        a[i]=sc(),bl[i]=(i-1)/block;
    pre();
    for(int i=1;i<=Q;i++)
        b[i].l=sc(),b[i].r=sc(),b[i].p=i;
    sort(b+1,b+Q+1,cmp);
    int L=1,R=0;
    for(int i=1;i<=Q;i++)
    {
        while(L>b[i].l)now+=call(L-1,R),L--;
        while(R<b[i].r)now+=calr(L,R+1),R++;
        while(L<b[i].l)now-=call(L,R),L++;
        while(R>b[i].r)now-=calr(L,R),R--;
        ans[b[i].p]=now;
    }
    for(int i=1;i<=Q;i++)
        printf("%lld\n",ans[i]);
    return 0;
}
时间: 2024-08-20 15:45:20

4540: [Hnoi2016]序列|莫队+ST表的相关文章

【BZOJ4542】[Hnoi2016]大数 莫队

[BZOJ4542][Hnoi2016]大数 Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也是P 的倍数).例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007:显然0077的子串007有6个子串都是素数7的倍数. Input 第一行一个整数:P.第二行一个串:S

Bzoj 3809: Gty的二逼妹子序列 莫队,分块

3809: Gty的二逼妹子序列 Time Limit: 35 Sec  Memory Limit: 28 MBSubmit: 868  Solved: 234[Submit][Status][Discuss] Description Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题. 对于一段妹子们,他们想让你帮忙求出这之内美丽度∈[a,b]的妹子的美丽度的种类数. 为了方便,我们规定妹子们的美丽度全都在[1,n]中. 给定一个长度为n(1<=n<=100000)的

[BZOJ4542] [Hnoi2016] 大数 (莫队)

Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也是P 的倍数).例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007:显然0077的子串007有6个子串都是素数7的倍数. Input 第一行一个整数:P.第二行一个串:S.第三行一个整数:M.接下来M行,每行两个整数

【序列莫队】BZOJ2038- [2009国家集训队]小Z的袜子(hose)

[题目大意]给出1-N只袜子的颜色,多次询问L-R中选出一双同色袜子的概率. [思路] 裸莫队.基本的莫队步骤:①分组(每组大小为根号sqrt(n),共sqrt(n)组)②排序(左边界分组,右边界在组内按大小排序)③暴力转移 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using name

4542: [Hnoi2016]大数|莫队

HN一天考两个莫队是什么鬼..或者说莫队不是正确的姿势..? 考虑已经知道了l..r的答案新添入r+1如何更新当前答案 需要先预处理出后缀modp的值bi,假设子序列l..r模p的值为x 那么x?10r?l+b[r]=b[l] 然后就可以直接莫队统计了 模数为2或5的时候要特判一下 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cs

bzoj 3809 Gty的二逼妹子序列 —— 莫队+分块

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3809 据说一开始应该想到莫队+树状数组,然而我想的却是莫队+权值线段树... 如果用权值线段树,则修改和查询都是 O(logn),总复杂度 O(n√nlogn),艰难...(而且仔细一看空间有点卡?) 看了TJ,才发现权值也可以分块,则查询 O(√n) 但修改 O(1),就可以过咯~ 代码如下: #include<iostream> #include<cstdio> #inc

CQOI2018异或序列 [莫队]

莫队板子 用于复习 #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #include <map> #define Sqr(x) ((x)*(x)) using namespace std; const int N = 1e5 + 5; struct Q{ int x, y, id; }q[N];

P4462 [CQOI2018]异或序列 莫队

题意:给定数列 \(a\) 和 \(k\) ,询问区间 \([l,r]\) 中有多少子区间满足异或和为 \(k\). 莫队.我们可以记录前缀异或值 \(a_i\),修改时,贡献为 \(c[a_i\bigoplus k]\) . #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #define R register in

[BZOJ4542] [JZYZOJ2014][Hnoi2016] 大数(莫队+离散化)

正经题解在最下面 http://blog.csdn.net/qq_32739495/article/details/51286548 写的时候看了大神的题解[就是上面那个网址],看到下面这段话 观察题目,发现一串数s(l~r)整除p满足s(l~n-1)%p==s(r+1~n-1)%p 但p值为2或5不满足这个性质需要特判(不过数据中好像没有,于是笔者没写,有兴趣的可以自己去写写......) 然后问题转化为求一段区间中有几对相等的f值. 看到这里,我感觉豁然开朗,完全忽视了离散化的要求,我以为把