题目链接:https://nanti.jisuanke.com/t/41399
解题思路:
首先我一开始没看空间的限制直接写了线段树,结果在测试的时候发现内存超限,然后考虑直接打标记,但是发现时间复杂度会超时,但是发现m最大只有1000,但是数值的大小却可以到1e6,这点符合离散化的特征,然后果断用离散化;
实现细节:首先讲所有的区间的2个端点放到vector中中进行离散化,然后开a,b数组,分别代表这个点往后会加1,这个点往前会加1;另外在分别开2个bool数组l, r,分别标记区间的左端点,右端点;
然后我们就可以直接遍历ve这个数组,这时我们需要用一个中间变量来记录当前所在区间一共加了几;
注意点:
1.在循环中需要分别判断3种情况
2.在跳出循环之后,还需要判断最后一个点是否被加过,如果被加过,则还需要更新中间变量。
AC代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#define isdigit(w) (w >= '0' && w <= '9')
using namespace std;
const int maxn = 2005;
struct Node {
int l, r;
}node[1005];
int T, n, m;
vector<int> ve;
int a[maxn], b[maxn];
bool l[maxn], r[maxn];
inline void read(int &x) {
x = 0; char w = getchar();
while(!isdigit(w)) w = getchar();
while(isdigit(w)) x = (x << 3) + (x << 1) + w - '0', w = getchar();
}
inline int find(int x) {
int l = 0, r = ve.size() - 1;
while(l < r) {
int mid = (l + r) >> 1;
if(ve[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}
int main(void) {
// freopen("in.txt", "r", stdin);
read(T);
int count = 1;
while(T --) {
read(n), read(m);
for(int i = 1; i <= m; i ++) {
read(node[i].l); read(node[i].r);
ve.push_back(node[i].l), ve.push_back(node[i].r);
}
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
for(int i = 1; i <= m; i ++) {
int ll = find(node[i].l), rr = find(node[i].r);
a[ll] ++, b[rr] --;
l[ll] = true, r[rr] = true;
}
int permt = 0, ans = 0;
for(int i = 0; i < ve.size() - 1; i ++) {
if(l[i] && !r[i]) {
permt += a[i];
if(permt % 2) ans += (ve[i + 1] - ve[i]);
} else if(!l[i] && r[i]) {
if(permt % 2) ans ++;
permt += b[i];
if(permt % 2) ans += (ve[i + 1] - ve[i] - 1);
} else {
permt += a[i];
if(permt % 2) ans ++;
permt += b[i];
if(permt % 2) ans += (ve[i + 1] - ve[i] - 1);
}
}
if(l[ve.size() - 1]) permt += a[ve.size() - 1];
if(permt % 2) ans ++;
printf("Case #%d: %d\n", count ++, ans);
for(int i = 0; i < ve.size(); i ++) {
a[i] = b[i] = 0;
l[i] = r[i] = false;
}
ve.clear();
}
// fclose(stdin);
return 0;
}
总结:感觉自己题目还是做少了,有了思路,但是写代码的速度太慢了。