题目描述
根据Sea Yellow,蓝色、白色、粉色的组合是最纯粹的! 现在有一个下标从1开始的数组a,长度为n,每个元素a都有一个额外的颜色属性。刚开始,所有的a0都是蓝色的,并且都等于0。然后,我们按顺序进行m次修改。每次修改会给出!.两个数,那么对于每个K==r,如果a而是蓝色的,那么它将变为白色,并+1;如果a是白色的,会变成粉色,并+1;如果ai是粉色的,会变成白色,并-2。请输出m次操作后的数组a(只需要输出数值,不需要输出颜色)。
输入:
第一行是整数n和m。1<=n,m<=1e5. 后面紧跟着m行,每行两个数,r,1<=<=r<=n。
输出:
输出一行n个整数。
示例 1:
输入:
6 3
1 3
3 4
3 6
输出:
1 1 0 2 1 1
解题思路
第一眼看到题目,一开始我用一个数组记录每次操作的颜色状态,根据颜色进行判断+1还是-2。后来看到题解,发现还可以用前缀和来解决问题。核心思想就是:数组a的颜色初始化是蓝色的,只要操作过一次就不会回去蓝色,只会在白色和粉色循环改变,因此可以利用被操作的次数的来+1或者-2。比如,下标i的元素,被操作4次,那么就会有4/2=2次是白色,也就是加了2次1,那么很自然,粉色次数 = 操作次数-白色的次数-蓝色次数。即4-2-1=1,需要减去1次2。所以问题就在如何求每个数组元素被操作的次数,这就是区间覆盖问题。
利用前缀和求区间被操作的次数:
维护一个数组v,遍历m次操作的左右区间[l,r],v[l]自增1,v[r+1]自减1。遍历m次后,对v进行前缀和,就可以得到前缀和数组,对于v[i],含义就是每个i下标的数组a被操作的次数。如此便得到了数组a每个元素被操作的次数。
需要注意的是,之所以是v[r+1]自减1,因为前面的v[l]已经加1了,超过r的元素都不会被操作,所以要抵消前面的v[l]自增的1。
代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[] v = new int[n+2];
for (int i = 0; i < m; i++) {
int l = scanner.nextInt();
int r = scanner.nextInt();
v[l]++;
v[r+1]--;
}
int first = 0;
for (int i = 1; i <= n; i++) {
v[i] += v[i-1];
first = v[i]==0?0:1;
// first表示蓝色出现的次数
System.out.print(first + v[i]/2 - (v[i]-v[i]/2-first)*2 + " ");
}
}
}