题目大致是有n个(long类型)棋子,棋子开始时全部朝上。有q次(q<300)查询输入,每次输入L,R(1<=L,R<=n)使得区间内的棋子从黑色变成白色,白色变成黑色。需要输出每次反转后有多少黑色棋子。
一、解题思路
1、看到区间修改,区间查询的题目应该直接想到线段树和树状数组。本题中的翻转操作可以转化为异或,初始全部为1(表示黑色棋子),翻转操作就是异或1。这样能够保证复杂度在nlogn。但本题中n太大,会爆内存所以肯定不是这种方法
2、求区间内有多少的问题,考虑维护前缀和(这种方法我不会)
3、同时考虑两次翻转的操作,不妨设输入为a,b,c,d且a<b<c<d。则有三种可能的情况,分别为[a.b],[c.d]、[a,c],[b,d]和[a,d],[b,c];
如图所示,图中阴影部分是实际翻转的棋子。不难发现三种组合情况的最终结果相同。故得出结论,左端点为偶数的区间影响最终结果。
注意到特例[1,1],[2.2](区间重合)的问题,左右端点相同对结果的贡献应当为1+1=2,而不是0。观察发现将左端点减一即可。
将所有输入排序,取出奇数段的长度进行统计。
二、AC代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
int q = sc.nextInt();
ArrayList<Long> list = new ArrayList<>();
for(int i=0;i<q;++i) {
long l=sc.nextLong();
long r=sc.nextLong();
l = l-1;//控制端点,比如1,1和2,2的用例
list.add(l);
list.add(r);
Collections.sort(list);//构造扫描线
long ans = n;
int size=list.size();
for(int j=0;j<size-1;++j)
{
if(j%2==0)//奇数段才会影响结果
{
long tmp = list.get(j+1)-list.get(j);
ans-=tmp;
}
}
System.out.println(ans);
}
sc.close();
}
}