LOJ.6284.数列分块入门8(分块)

Posted SovietPower

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LOJ.6284.数列分块入门8(分块)相关的知识,希望对你有一定的参考价值。

题目链接

\(Description\)

给出一个长为n的数列,以及n个操作,操作涉及区间询问等于一个数c的元素,并将这个区间的所有元素改为c。

\(Solution\)

模拟一些数据可以发现,询问后一整段都会被修改,几次询问后数列可能只剩下几段不同的区间了。
那么还是暴力,每个块维护的是整个块是否仅被一种权值覆盖。查询时对于相同权值的块就可以O(1)统计;否则暴力统计并修改答案;不完整的块暴力。
这样看似最差情况下每次需要O(n)的时间,但实际远远到不了
假设初始序列都是同一个值,那么查询需要O(sqrt(n)),如果这时进行区间修改,那么最多会破坏首尾两个块的标记
所以只能使后面的询问至多多2个块的暴力时间,所以均摊每次操作复杂度为O(sqrt(n))
换句话说,要想让一个操作耗费O(n)的时间,要先花费sqrt(n)个操作修改数列
----by hzwer

#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e5+5,MAXIN=1e6;

int n,size,sizen,A[N],tag[2000],bel[N],L[2000],R[2000];
bool cover[2000];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
int Count(int l,int r,int v)
{
    int res=0;
    for(int i=l; i<=r; ++i)
        if(A[i]==v) ++res; else A[i]=v;
    return res;
}
void Reset(int p,int l,int r,int vbef,int v)
{//Reset [L(p),l)&&(r,R(p)] to vbef,[l,r] to v
    for(int i=L[p]; i<l; ++i) A[i]=vbef;
    for(int i=l; i<=r; ++i) A[i]=v;
    int t=std::min(n,R[p]);
    for(int i=r+1; i<=t; ++i) A[i]=vbef;
    cover[p]=0;
}
int Get_scatter(int l,int r,int v)
{
    if(cover[bel[l]])
        if(tag[bel[l]]==v) return r-l+1;
        else Reset(bel[l],l,r,tag[bel[l]],v);
    else return Count(l,r,v);
    return 0;
}
int Query(int l,int r,int v)
{
    int res=Get_scatter(l,std::min(r,R[bel[l]]),v);

    if(bel[l]!=bel[r]) res+=Get_scatter(L[bel[r]],r,v);

    for(int i=bel[l]+1; i<bel[r]; ++i)
        if(cover[i])
            if(tag[i]==v) res+=bel[l]==bel[n]?sizen:size;
            else tag[i]=v;
        else
            res+=Count(L[i],R[i],v), cover[i]=1, tag[i]=v;
    return res;
}

int main()
{
    n=read(), size=sqrt(n);
    for(int i=1; i<=n; ++i) bel[i]=(i-1)/size+1, A[i]=read();
    for(int i=1; i<=bel[n]; ++i) L[i]=(i-1)*size+1,R[i]=i*size;
    sizen=n-(bel[n]-1)*size;
    for(int l,r,c,i=1; i<=n; ++i)
        l=read(), r=read(), c=read(), printf("%d\n",Query(l,r,c));
    return 0;
}

以上是关于LOJ.6284.数列分块入门8(分块)的主要内容,如果未能解决你的问题,请参考以下文章

Loj 6284. 数列分块入门 8

数列分块入门8 解题报告

数列分块入门7 解题报告

数列分块入门9 解题报告

数列分块入门3 解题报告

数列分块入门6 解题报告