题目:改变数组元素
给一个空数组v和一个整数数组a,对数组v进行n次操作,第i次操作为在数组v尾部插入整数0,将位于数组v尾部的a[i]个元素都变为1。这里需要注意a[i]可能为0,该情况不做任何改变,a[i]也可能大于当前数组v的元素个数,此时把数组v内所有元素都变为1。
输入有T组测试数据,每组数据第一行输入整数n,第二行输入n个整数,这里T最大20000,n最大200000,并且每一个测试点内的n的和不超过200000,那么一次遍历最多20000x200000,因此时间复杂度要控制在O(nlogn)以内。
本题实际上是把某一个区间内的元素变成1,因此可以用差分法解决,差分法主要解决的问题是某个区间所有元素都加上一个数,本题也可以转化为每个元素都加上一个数的形式。
差分
一维差分
差分就是前缀和的逆运算,对于前缀和数组a,a[i]是自己以及前面所有元素的和,也即a[i]=a[i]+a[i-1],再设一个数组b,a[i]=b[1]+b[2]+...+b[i],对于这样的两个数组,数组a是数组b的前缀和,数组b是数组a的差分。
差分的用处在于,当我们把一个区间[l,r]同时加上或减去同一个数tmp,可以直接遍历,时间复杂度为O(n),如果要进行m次相加或相减,时间复杂度为O(n*m),这样时间复杂度过高。此时可以用差分数组,[l,r]区间加上(或减去)tmp等价于差分数组[l]+tmp,[r+1]-tmp,这样计算前缀和时,[l+1]=[l+1]+[l],也即[l+1]也加上了tmp,到[r+1]时,该元素先减去一个tmp,后加上一个tmp,前后相抵消,此时只有[l,r]区间都加上了tmp,并且时间复杂度为O(n)。
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 200000+10;
int T,n,a[N];
int main()
{
cin>>T;
while(T--)
{
int tmp;
cin>>n;
//memset(a, 0 ,sizeof(a));
memset(a, 0, (n+1)*4);
for(int i=1; i<=n; ++i)
{
cin>>tmp;
tmp=min(tmp, i);
int l=i-tmp+1, r=i;
a[l]++, a[r+1]--;
}
for(int i=1; i<=n; ++i) a[i]+=a[i-1];
for(int i=1; i<=n; ++i)
{
if(a[i]) cout<<"1 ";
else cout<<"0 ";
//cout<<!!a[i];
//如果a[i]不为0,!a[i]为0,!!a[i]就为1,也即a[i]被操作过就是1,同理当a[i]为0时,结果为0
}
cout<<endl;
}
return 0;
}
这里memset的写法只初始化可能用到的地方(一个int是4个字节,所以乘4),节省时间。
标签:tmp,int,元素,差分,算法,数组,include From: https://www.cnblogs.com/HD0117/p/17131373.html