【分块】八

  因为分块四开始,到分块九,都不是我们组的任务,所以,,我选择直接写分块八。

  其他题目你们可以直接去黄哲威的博客(嘤嘤嘤黄哲威的名字已经被我安利好几遍了,放心我没有被付广告费)

 

先看题面:

题目描述

题目背景:

国民男神ty再次遇到了一个小难题,这次他在和另一个大神的交流中ty表示自己会这个问题,但他想给你一个表现的机会,于是他将这个问题交给了你。

题目描述:

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

输入

第一行:一个整数n,表示数列长为n,以及有n次操作。

第二行:n个数,表示原来的数列。

3~n+2行:每行个数:l,r,x,区间l~r,和查询和修改的元素x

输出

n行,每行一个数,输出lr区间内已修改完的值为x的元素个数和

样例输入

4

1 2 3 4

1 2 1

1 3 2

3 4 2

2 3 2

样例输出

1

0

1

2

提示

对于50%的数据 n<=1000

对于100%的数据 n<=70000

保证运算过程中数据不超过64位整数

保证数据全部随机

 

:那个你是不是发现题目的格式and题目的类型特别相似嘤嘤嘤,好的我就是把上次第三道改了一下。(我才没有黑ty)

 

 

 

【题目解析】

 

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

 

区间加法前面已经讲了多次了,暂不阐述,这里详细讲述一下查询。

 

 

 

//预备:有若干个数组blocktag,block指每个数所在的块的序,tag用来储存每个完整块的变化量。

 

 

 

查询的难处在于,元素的权值有多个,较难判断。

 

如果照正常的方法,我们应该将每个数都暴力搜一遍,但时间复杂度不容乐观,所以我们需要仔细观察。多模拟几个数据,发现询问后一整段都会被修改,几次询问后数列可能只剩下几段不同的区间了。

 

 

 

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

 

(没毛病,这里直接摘取了黄哲威学长的原话)

 

 

 

这样的时间复杂度就瞬间降低了。

 

 

 

其他细节可以看ac代码。

 

 

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,blo;
int v[100005],block[100005],tag[100005];
void reset(int x)
{
    if(tag[x]==-1) return;
    for(int i=(x-1)*blo+1;i<=blo*x;i++) v[i]=tag[x];
    tag[x]=-1;
}
int solve(int a,int b,int c)
{    
    int ans=0;
    reset(block[a]);
    for(int i=a;i<=min(block[a]*blo,b);i++) v[i]=c;
      else ans++;
         
    if(block[a]!=block[b])
    {
        reset(block[b]);
        for(int i=(block[b]-1)*blo+1;i<=b;i++) v[i]=c;
           else ans++;
    }
    for(int i=block[a]+1;i<=block[b]-1;i++)
        if(tag[i]!=-1)
        {
            if(tag[i]!=c)tag[i]=c;
            else ans+=blo;
        }
        else
        {
            for(int j=(i-1)*blo+1;j<=i*blo;j++) v[j]=c;
                 else ans++;
            tag[i]=c;
        }    
    return ans;
}

int main()
{
    memset(tag,-1,sizeof(tag));
    scanf("%d",&n);
    blo=sqrt(n);
    for(int i=1;i<=n;i++) scanf("%d",&v[i]);
    for(int i=1;i<=n;i++) block[i]=(i-1)/blo+1;
    for(int i=1;i<=n;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        printf("%d\n",solve(a,b,c));
    }
    return 0;
}

 

 

 

是不是很惊讶我明明还在c++从入门到放弃的过程,现在已经可以编了???

 

那是因为我废寝忘食(鬼信哦),好吧我等会儿是要去练习c++咯,如果有空的话还会更新练习情况嘤嘤嘤(反正没人看我博客我也不管啦什么都往上搬,大概没人会打我hhhh)

 

 

好啦分块的专题至此结束。。

感谢黄哲威学长(学长看到估计已经快吐了),感谢帮助过我的队友and好朋友。

 

希望oi之路更加interesting(误)

 

posted @ 2017-06-01 14:50  Hathawaxy  阅读(331)  评论(2编辑  收藏  举报