ACM/ICPC 之 数据结构-线段树+区间离散化(POJ2528)
这道题用线段树做更方便更新和查询,但是其数据范围很大,因此要将离散化和线段树结合起来,算是一道比较经典的线段树+离散化的例题。
线段树的离散化有很多方法,在这里,我先用一次结点离散化,间接将源左右端点离散化的想法实现。(受到一个博客的启发)
题意:贴海报-给出海报左右端点,然后顺序贴上,问最后有多少海报可见。
直接贴上Code,具体解释在注释中有提及(有不懂的地方可以在纸上打个线段树草稿试试):
//贴海报-给出海报左右端点,顺序贴上,问最后有多少海报可见。 //Time:79Ms Memory:2712K #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define MAX 10005 struct Node { int l, r, kind; }tr[16*MAX]; //两端点加空点需要8-16*MAX数据量 struct Pos { int num, id; friend bool operator < (Pos p1, Pos p2) { return p1.num < p2.num; } }pos[2*MAX]; int n, cnt; int l[MAX], r[MAX]; bool v[MAX]; void build(int x,int l,int r) { tr[x].l = l; tr[x].r = r; if (l == r) return; int mid = (l + r) / 2; build(2 * x, l, mid); build(2 * x + 1, mid + 1, r); } void update(int x,int l,int r,int k) { if (tr[x].l == l && tr[x].r == r) { tr[x].kind = k; return; } if (tr[x].kind) { tr[2 * x].kind = tr[x].kind; tr[2 * x + 1].kind = tr[x].kind; tr[x].kind = 0; } int mid = (tr[x].l + tr[x].r) / 2; if (r <= mid) update(2 * x, l, r, k); else if (l > mid) update(2 * x + 1, l, r, k); else { update(2 * x, l, mid, k); update(2 * x + 1, mid + 1, r, k); } } int query(int x,int l,int r) { if (tr[x].kind) { if (v[tr[x].kind]) return 0; else { v[tr[x].kind] = true; return 1;} } if (tr[x].l == tr[x].r) return 0; //由于有空点,可能会有tr[x].kind = 0 int mid = (tr[x].l + tr[x].r) / 2; return query(2 * x, l, mid) + query(2 * x + 1, mid + 1, r); } int main() { int T; scanf("%d", &T); while (T--) { memset(tr, 0, sizeof(tr)); memset(v, 0, sizeof(v)); scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d%d", &l[i], &r[i]); pos[2 * i].num = l[i]; pos[2 * i + 1].num = r[i]; pos[2 * i].id = 2 * i; //偶数-左端点 pos[2 * i + 1].id = 2 * i + 1; //奇数-右端点 } int last = pos[0].num; cnt = 1; sort(pos, pos + 2 * n); for (int i = 0; i < 2 * n; i++) { if (last != pos[i].num) { if (pos[i].num - last > 1) cnt++; //不相邻时,中间空一点 cnt++; last = pos[i].num; } int id = pos[i].id; //分别对左右端点离散化 id % 2 ? r[id/2] = cnt : l[id/2] = cnt; } build(1, 1, cnt); for (int i = 0; i < n; i++) update(1, l[i], r[i], i + 1); printf("%d\n", query(1, 1, cnt)); } return 0; }
他坐在湖边,望向天空,她坐在对岸,盯着湖面