POJ
来源:互联网 发布:网络上gem是什么意思 编辑:程序博客网 时间:2024/06/14 17:46
现已发现数据卡掉程序,暂未修改!
题目链接:
题目大意:
数据范围:
解题思路:
外话:
在我理解看来就是将一个很大的区间映射为一个很小的区间,而不改变原有的大小覆盖关系,但是注意简单的离散化可能
会出现错误,给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10
普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖解决的办法则是对于距离大于1的两相邻点,中间再插入一个点,本题还用到了Lazy标记的思想
代码采用端点表示区间的方法:
#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#include <set>#include <map>#include <queue>using namespace std;typedef long long LL;const int inf = 1 << 30;const LL INF = 1LL << 60;const int MaxN = 1e4;int T;int n, tot, m;int ans;int le[MaxN + 5], ri[MaxN + 5];int x[4 * MaxN + 5];bool vis[16 * MaxN + 5];struct segtree{ int l, r;}tree[16 * MaxN + 5];int col[16 * MaxN + 5];//节点的颜色,相当于lazy数组,若col[i] == -1则没有染色void Build(int rt, int l, int r){ tree[rt].l = l, tree[rt].r = r; if(l == r) return; int mid = (l + r) >> 1; Build(rt << 1, l, mid); Build(rt << 1 | 1, mid + 1, r);}void push_down(int rt){ if(col[rt] != -1) { col[rt << 1] = col[rt]; col[rt << 1 | 1] = col[rt]; col[rt] = -1; }}void update(int rt, int L, int R, int c){ //若所要染色的区间完全包含 当前节点所管辖的区间 //直接将这个节点染色,不必再往下染色了 if(L <= tree[rt].l && tree[rt].r <= R) { col[rt] = c; return ; } //否则下放标记,即对左右儿子染色 push_down(rt); int mid = (tree[rt].l + tree[rt].r) >> 1; if(L <= mid) update(rt << 1, L, R, c); if(R > mid) update(rt << 1 | 1, L, R, c);}void query(int rt){ if(col[rt] != -1) { //说明这个节点所管辖的区间是纯色 if(vis[col[rt]] == false) { ans++; vis[col[rt]] = true; } return; } push_down(rt); //这个不用都能过,想想why? if(tree[rt].l == tree[rt].r) return; query(rt << 1); query(rt << 1 | 1);}//查找数组中第一个小于等于y的值的位置,相当于lower_boundint bin_search(int y){ int l = 1, r = m; int mid = 0, res = 0; while(l <= r) { mid = (l + r) >> 1; if(x[mid] >= y) res = mid, r = mid - 1; else l = mid + 1; } return res;}int main(){ scanf("%d", &T); while(T--) { ans = 0; tot = 0; memset(col, -1, sizeof(col)); memset(vis, 0, sizeof(vis)); scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d %d", &le[i], &ri[i]); x[++tot] = le[i]; x[++tot] = ri[i]; } //--------离散化------ sort(x + 1, x + tot + 1); m = 1; for(int i = 2; i <= tot; i++) { if(x[i] != x[i - 1]) //去重 x[++m] = x[i]; } sort(x + 1, x + m + 1); Build(1, 1, m); //对离散后的数组进行建树 for(int i = 1; i <= n; i++) { //二分查找到离散后的新区间 int newl = bin_search(le[i]); int newr = bin_search(ri[i]); //将新区间染色i这种颜色 update(1, newl, newr, i); } ans = 0; query(1); printf("%d\n", ans); memset(tree, 0, sizeof(tree)); } return 0;}