loj 6284 数列分块入门 8

http://www.elijahqi.win/2018/03/05/loj-6284/
题目描述

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

输入格式

第一行输入一个数字 nnn。

第二行输入 nnn 个数字,第 i 个数字为 aia_ia​i​​,以空格隔开。

接下来输入 nnn 行询问,每行输入三个数字 lll、rrr、ccc,以空格隔开。

表示先查询位于 [l,r][l,r][l,r] 的数字有多少个是 ccc,再把位于 [l,r][l,r][l,r] 的数字都改为 ccc。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

4
1 2 2 4
1 3 1
1 4 4
1 2 2
1 4 2
样例输出

1
1
0
2
数据范围与提示

对于 100% 100\% 100% 的数据,1≤n≤100000,−231≤others 1 \leq n \leq 100000, -2^{31} \leq \mathrm{others}1≤n≤100000,−2​31​​≤others、ans≤231−1 \mathrm{ans} \leq 2^{31}-1 ans≤2​31​​−1。

直接非常暴力搞就可以 因为一个操作必定连接着一个染色操作 所以假设我需要让所有块都暴力重构 那么我必定需要sqrt(n)个前置操作才可以实现 所以总的复杂度是n*sqrt(n)的

怎么暴力 就每个区间打一个懒标记 如果有懒标记并且==c那么直接统计区间长度 否则就暴力扫一遍

#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 110000
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,nn,a[N],ri[N],lf[N],b[N],len[N];
int lazy[N];bool tag[N];
int main(){
    freopen("a1.in","r",stdin);
    freopen("aa1.out","w",stdout);
    n=read();nn=sqrt(n);int nx=(n-1)/nn+1;
    for (int i=1;i<=n;++i) {a[i]=read();b[i]=(i-1)/nn+1;}
    for (int i=1;i<nx;++i) lf[i]=(i-1)*nn+1,ri[i]=i*nn,len[i]=nn;
    lf[nx]=(nx-1)*nn+1;ri[nx]=n;len[nx]=n-(nx-1)*nn;
    for (int ii=1;ii<=n;++ii){
        int l=read(),r=read(),c=read(),tmp=0;
        //for (int i=1;i<=10;++i) printf("%d ",a[i]);puts("");
        if (b[l]==b[r]){
            if(tag[b[l]]) {for (int i=lf[b[l]];i<=ri[b[l]];++i) a[i]=lazy[b[l]];tag[b[l]]=0;}
            for (int i=l;i<=r;++i) tmp+=(a[i]==c),a[i]=c;printf("%d\n",tmp);continue;
        }
        for (int i=b[l]+1;i<b[r];++i){
            if (!tag[i]) {
                for (int j=lf[i];j<=ri[i];++j) tmp+=(a[j]==c),a[j]=c;
                lazy[i]=c;tag[i]=1;continue;
            }if (tag[i]&&lazy[i]==c) tmp+=len[i];lazy[i]=c;tag[i]=1;
        }
        if(tag[b[l]]) {for (int i=lf[b[l]];i<=ri[b[l]];++i) a[i]=lazy[b[l]];tag[b[l]]=0;}
        for (int i=l;i<=ri[b[l]];++i) tmp+=(a[i]==c),a[i]=c;
        if(tag[b[r]]) {for (int i=lf[b[r]];i<=ri[b[r]];++i) a[i]=lazy[b[r]];tag[b[r]]=0;}
        for (int i=lf[b[r]];i<=r;++i) tmp+=(a[i]==c),a[i]=c;printf("%d\n",tmp);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值