题目连接
题意:
N 个 灯泡(编号 0 ~ N-1) M 次操作(初始灯都是关的)
每次操作 给 2个数 L, R,把[L, R]区间内的开关翻转
求 M次操作后 有多少灯开着
数据范围 :
时间 1e9
T组样例 1e3
N 1e6
M 1e3
0 <= L,R <= N -1
思路:
看到区间操作 区间更新 就想 线段树,和差分数组
算下时间 每组样例 1e6
1)线段树
2)差分数组
3)直接差分后 还要有个O(N)遍历 所以 不可行,
4)M很小,我们可以从M入手
5)发现我们只需要考虑 2*M个有贡献的点就行了对与区间内的0 不需要遍历
AC:
#include<iostream>
#include<cstring>
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<map>
using namespace std;
const int maxn = 2e3 + 10;
int N, M;
pair<int, int> p[maxn];
int main() {
int T, Case = 0;
scanf("%d", &T);
int Cnt = 0;
while(T--) {
Cnt = 0;
scanf("%d%d", &N, &M);
int L, R;
for(int i = 1; i <= M; ++i) {
scanf("%d%d", &L, &R);
p[Cnt++] = make_pair(L, 1);
p[Cnt++] = make_pair(R + 1, -1);
}
sort(p, p + Cnt);
int Ans = 0;
int Sum = 0;
for(int i = 0; i < Cnt; ++i) {
Sum += p[i].second;
if(Sum & 1)//如果这个开关是开的 ,那到下个最近的灯泡操作前灯都是开的
Ans += p[i + 1].first - p[i].first;
}
printf("Case #%d: %d\n", ++Case, Ans);
}
return 0;
}