数列分块入门8 LibreOj 6284

13 篇文章 0 订阅
11 篇文章 0 订阅

题意

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

思路

        我们这里用flag标志数组,其作用类似于之前的lazy数组,如果flag=-1,那么代表这一块还没有被整体赋值,如果flag\neq-1,那么代表这一块是整体赋值了的,如果flag[i]==c,那么代表这一块都是c,那么ans+=block(块的长度);如果flag[i]!=c,那么就更新为c,ans不变化。

        对于不完整块,我们首先看flag是否更改过,如果更改过,那我们首先先reset一下,reset的作用是将这一块暴力赋值为flag存的数,然后再在[l,r]的区间内暴力询问c、修改c。

代码

#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N = 200007;
const int M = 10007;
int l[N],r[N],block,num,belong[N],n,x,y;
int a[N],lazy[N],b[N],sum[N],mul[N],flag[N];
inline void build()
{
    block=sqrt(n);
    num=n/block;if (n%num) num++;
    for (int i=1;i<=num;i++)
        l[i]=(i-1)*block+1,r[i]=i*block;
    r[num]=n;
 
    for (int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;

    for (int i=1;i<=num;i++)
        flag[i]=-1;
    //开始全部为-1
}
inline void reset(int x)
{
    int o=belong[x];
    for (int i=l[o];i<=r[o];i++)
        a[i]=flag[o];
    flag[o]=-1;
    //flag已经全部给该块,已经没有用了
}
inline int ask(int x,int y,int c)
{
    int ans=0;
    if (belong[x]==belong[y])
    {
        if (flag[belong[x]]!=-1) reset(x);
        for (int i=x;i<=y;i++)
        {
            if (a[i]==c) ans++;
            a[i]=c;
        }
        //暴力求解
        return ans;
    }
    if (flag[belong[x]]!=-1) reset(x);
    for (int i=x;i<=r[belong[x]];i++)
    {
        if (a[i]==c) ans++;
        a[i]=c;
    }
    if (flag[belong[y]]!=-1) reset(y);
    for (int i=l[belong[y]];i<=y;i++)
    {
        if (a[i]==c) ans++;
        a[i]=c;
    }
    
    for (int i=belong[x]+1;i<belong[y];i++)
    {
        if (flag[i]!=-1)
        {
            if (flag[i]==c) ans+=block;
        }
        else
        {
            for (int j=l[i];j<=r[i];j++)
            {
                if (a[j]==c) ans++;
            }
        //没修改过的用暴力求解
        }
        flag[i]=c;
        //这一整块都是c
    }
    return ans;
}
signed main() 
{
    #ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
    IOS
    int m;
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    build();
    for (int k=1;k<=n;k++)
    {
        int l,r,op;
        int c;
        cin>>l>>r>>c;
        cout<<ask(l,r,c)<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值