题目链接:https://loj.ac/problem/6284
题目大意:

区间修改没有什么难度,这题难在区间查询比较奇怪,因为权值种类比较多,似乎没有什么好的维护方法。

模拟一些数据可以发现,询问后一整段都会被修改,几次询问后数列可能只剩下几段不同的区间了。

我们思考这样一个暴力,还是分块,维护每个分块是否只有一种权值,区间操作的时候,对于同权值的一个块就O(1)统计答案,否则暴力统计答案,并修改标记,不完整的块也暴力。

这样看似最差情况每次都会耗费O(n)的时间,但其实可以这样分析:

假设初始序列都是同一个值,那么查询是O(√n),如果这时进行一个区间操作,它最多破坏首尾2个块的标记,所以只能使后面的询问至多多2个块的暴力时间,所以均摊每次操作复杂度还是O(√n)。

换句话说,要想让一个操作耗费O(n)的时间,要先花费√n个操作对数列进行修改。

初始序列不同值,经过类似分析后,就可以放心的暴力啦。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//由块号寻找第一个块元素的下标
#define LL(x) ((x-1)*Len+1)
const int mod=10007;
LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int a[100005], b[100005], flag[1005];
int Len, n;

void reset(int x)//标记下推
{
    if(flag[x]==-1)
    {
        return;
    }
    for(int i=LL(x);i<=min(LL(x+1)-1, n);i++)
    {
        a[i]=flag[x];
    }
    flag[x]=-1;
}

int query(int L, int R, int c)
{
    int bL=b[L], bR=b[R];
    int ans=0;
    if(bL==bR)
    {
        reset(bL);
        for(int i=L;i<=R;i++)
        {
            if(a[i]==c)
            {
                ans++;
            }
            a[i]=c;
        }
    }
    else
    {
        reset(bL);//标记下推
        for(int i=L;i<LL(bL+1);i++)//暴力边块
        {
            if(a[i]==c)
            {
                ans++;
            }
            a[i]=c;
        }

        for(int i=bL+1; i<bR; i++)
        {
            if(flag[i]!=-1)
            {
                if(flag[i]==c)//如果是一整块(全部相同)
                {
                    ans+=Len;
                }
            }
            else
            {
                for(int k=LL(i); k<LL(i+1); k++)//如果不是整块(不全部相同)
                {
                    if(a[k]==c)
                    {
                        ans++;
                    }
                    a[k]=c;
                }
            }
            flag[i]=c;
        }

        reset(bR);//标记下推
        for(int i=LL(bR);i<=R;i++)//暴力边块
        {
            if(a[i]==c)
            {
                ans++;
            }
            a[i]=c;
        }
    }

    return ans;
}

void build(int n)
{
    Len=n/sqrt(n);
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        b[i]=(i-1)/Len+1;
        flag[b[i]]=-1;
    }
}

int main()
{
    n=read();
    build(n);

    for(int i=1;i<=n;i++)
    {
        int L=read(), R=read(), c=read();

        printf("%d\n",query(L, R, c));
    }

    return 0;
}