【分块】八
因为分块四开始,到分块九,都不是我们组的任务,所以,,我选择直接写分块八。
其他题目你们可以直接去黄哲威的博客(嘤嘤嘤黄哲威的名字已经被我安利好几遍了,放心我没有被付广告费)
先看题面:
题目描述
题目背景:
国民男神ty再次遇到了一个小难题,这次他在和另一个大神的交流中,ty表示自己会这个问题,但他想给你一个表现的机会,于是他将这个问题交给了你。
题目描述:
给出一个长为n的数列,以及n个操作,操作涉及区间询问等于一个数c的元素,并将这个区间的所有元素改为c。
输入
第一行:一个整数n,表示数列长为n,以及有n次操作。
第二行:n个数,表示原来的数列。
第3~n+2行:每行三个数:l,r,x,区间l~r,和查询和修改的元素x。
输出
共n行,每行一个数,输出l到r区间内已修改完的值为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。
区间加法前面已经讲了多次了,暂不阐述,这里详细讲述一下查询。
//预备:有若干个数组block、tag,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(误)