POJ - 2528 线段树+离散化
其实很早就在白书上的常用技巧上 看到离散化的操作,但是之前一直没遇到过需要离散化的题目(应该是我太菜的缘故),所以一直也没怎么重视,下面说说这道题目的考点,也就是离散化。
什么是离散化呢?请先自行百度理解了,一定先了解后再往下看。
那么该如何进行操作呢?
举个例子
假如 我们有5个数
36 63431 986357 850159901 2147483640
很明显 它们的大小关系为 36 < 63431 < 986357 < 850159901 < 2147483640
但是,我们并不需要知道 36 63431 986357 850159901 2147483640 它们实际的大小,只需要知道它们的相对大小就可以了
所以我们可以把 36转化为 1 63431转化为2 986357转化为3 850159901转化为4 2147483640转化为5
这样我们得到了新的5个数 也就是 1 2 3 4 5
同时,它们的相对大小还是一样的 1<2<3<4<5
再用题目中的数据来举个例子
1 5 1 4 2 6 8 10 3 4 7 10
我们得到了5个范围,也就是1~4, 2~6, 8~10, 3~4, 7~10.
同样的,我们并不需要知道它们的实际范围,只需要知道它们的相对范围就可以了
我们把它们每个点都整合起来 所以就是 1 2 3 4 4 6 7 8 10 10
然后去掉重复的点 剩下 1 2 3 4 6 7 8 10
离散化得到新的范围 1~4, 2~5, 7~8, 3~4, 6~8
画个图会发现,新的范围 和 旧的范围 的 相对范围,其实是一样的.
下面是这道题的思路:
线段树方面是常规操作,关键是这个离散化就有点特殊了
首先我们测试下这个数据
1
3
1 10
1 4
6 10
会发现常规的离散化会覆盖点5这个点,而得到答案2,但是应该是3才对
这时候我们需要把每个点的右边的数加入 离散化的操作中来保证 连续性
(但是这个题目的数据太弱,导致错误的离散化也可以AC)
#include <algorithm> #include <iostream> #include<sstream> #include<iterator> #include<cstring> #include<string> #include<cstdio> #include<cctype> #include<vector> #include<deque> #include<map> #include<set> #define M 100005 #define inf 0x3f3f3f3f typedef long long ll; using namespace std; int T, n; int x, y, z; set<int>ans; vector<int>num; struct Data { int l, r, val, lazy; }tree[8*M]; struct Data_x { int u, v; }loc_[M], loc[M];//loc_c是最初的数据,loc是离散后的数据 void built(int l, int r, int k) { tree[k].l = l, tree[k].r = r; tree[k].val = tree[k].lazy = 0; if (l == r)return; int mid = (l + r) / 2; built(l, mid, k << 1); built(mid + 1, r, (k << 1) | 1); } void down(int k) { tree[k << 1].val = tree[k << 1].lazy = tree[k].lazy; tree[(k << 1) | 1].val = tree[(k << 1) | 1].lazy = tree[k].lazy; tree[k].lazy = 0; } void change(int k) { if (tree[k].l >= x && tree[k].r <= y) { tree[k].val = z; tree[k].lazy = z; return; } if (tree[k].lazy)down(k); int mid = (tree[k].l + tree[k].r) / 2; if (x <= mid)change(k << 1); if (y > mid)change((k << 1) | 1); if (tree[k << 1].val == tree[(k << 1) | 1].val) tree[k].val = tree[k << 1].val; else tree[k].val = -1; } void cal(int k) { if (tree[k].val>0) { ans.insert(tree[k].val); return; } if (!tree[k].val) return; cal(k << 1); cal((k << 1) | 1); } int main() { cin >> T; while (T--) { cin >> n; ans.clear(); num.clear(); for (int i = 1; i <= n; i++) { scanf("%d%d", &loc_[i].u, &loc_[i].v);//读入最初的数据、 //把所有的点整合在一起 num.push_back(loc_[i].u); num.push_back(loc_[i].v); //保证连续性 num.push_back(loc_[i].u + 1); num.push_back(loc_[i].v + 1); } sort(num.begin(), num.end()); vector<int>::iterator iter = unique(num.begin(), num.end());//去重 //得到新的范围 for (int i = 1; i <= n; i++) { loc[i].u = lower_bound(num.begin(), iter,loc_[i].u) - num.begin(); loc[i].v = lower_bound(num.begin(), iter, loc_[i].v) - num.begin(); loc[i].u++; loc[i].v++; } built(1, M, 1); for (int i = 1; i <= n; i++) { x = loc[i].u, y = loc[i].v, z = i; change(1); } cal(1); cout << ans.size() << endl; } return 0; }