【解题报告】POJ-2528 Mayor's posters 线段树+离散化

来源:互联网 发布:江西淘宝村 编辑:程序博客网 时间:2024/06/12 16:26

题目大意:有一面一千万长的墙,往墙上贴海报,海报的宽度给出。问最后一共能看到几面海报。

第一反应必然是线段树,但是一千万的线段树必然超内存,所以要离散化。因为我们其实只需要用到海报开始和结束的那两个位置。

这道题的难点在于如何离散化。

如果按照每个点来离散,会出现问题。就用其他题解给出的例子:

(1,10),(1,4),(6,10)。离散完就是1234四个叶子结点。

那么更新(1,4)时,1-2这段区间被覆盖,更新(6,10)时,3-4区间被覆盖。那么最后查询的时候会发现(1,10)被完全覆盖了。但是,事实上,应该有(5,5)这个区间没有被覆盖。

那么如何解决呢?

搜了网上的题解,说在x相差大于1时加入一个中间节点。在我看来,这就是一坨屎。

我的方法是,参考扫描线解题的过程。因为海报覆盖的是一个个点,我们把点变为块然后离散到数轴上,那么每一个点x都可以变为一段区间(x,x+1)。那么线段树存取什么呢,存取的是一段段区间。就拿上述例子来说,用我的离散方法,数轴被划分为1,5,6,11四个点。那么在线段树内就有三个叶子结点:(1,5)(5,6)(6,11)这样三个区间。这样就完美的解决了中间的5被覆盖的问题。

下面给出代码:

#include <iostream>#include <string.h>#include <algorithm>#include <cstdio>#include <set>using namespace std;typedef long long ll;#define INF 0x3f3f3f3f#define lc n << 1#define rc n << 1 | 1const int maxp = 100005;//注意,用10005还是会数组超界,多开十倍即可struct segtree {int l, r, id, lazy;//lazy表示这一段被染过色了int lx, rx;bool u;//u表示这个节点的子节点需不需要更新}t[maxp << 3];struct flag {int l, r;}f[maxp];int x[maxp << 2];bool cs[maxp];inline int getlen(int n) { return t[n].r - t[n].l + 1; }inline void push_down(int n){t[lc].lazy = t[n].lazy;t[rc].lazy = t[n].lazy;t[lc].id = t[n].lazy;t[rc].id = t[n].lazy;t[lc].u = t[rc].u = true;t[n].u = false;}void build(int n,int l, int r){t[n].l = l, t[n].r = r;t[n].lazy = 1;t[n].u = false;t[n].lx = x[l], t[n].rx = x[r];t[n].id = 0;if (l + 1 == r) { return; }int mid = (l + r) >> 1;build(lc, l, mid);build(rc, mid, r);}void update(int n, int l, int r, int a){if (l > t[n].rx || r < t[n].lx)return;if (l <= t[n].lx && r >= t[n].rx){t[n].lazy = a;t[n].u = true;t[n].id = a;return;}if(t[n].u)push_down(n);update(lc, l, r, a);update(rc, l, r, a);}int query(int n, int l, int r){if (l > t[n].rx || r < t[n].lx)return 0;if (l == t[n].lx && r == t[n].rx)return t[n].id;if(t[n].u)push_down(n);if (r <= t[lc].rx)return query(lc, l, r);if (l >= t[rc].lx)return query(rc, l, r);}int main(){int T, n, q, l, r, temp;cin >> T;for (int C = 1;C <= T;C++){set<int>LX;memset(x, 0, sizeof x);memset(cs, 0, sizeof cs);memset(t, 0, sizeof t);cin >> n;q = 0;for (int i = 1;i <= n;i++){scanf("%d%d", &l, &r);f[i].l = l;f[i].r = r + 1;if (!LX.count(l))//这里使用set为了使区间不出现(x,x)这样的无意义区间{x[++q] = l;LX.insert(l);}if (!LX.count(r + 1)){x[++q] = r + 1;LX.insert(r + 1);}}sort(x + 1, x + q + 1);build(1, 1, q);for (int i = 1;i <= n;i++)update(1, f[i].l, f[i].r, i);int ans = 0;for (int i = 1;i < q;i++){temp = query(1, x[i], x[i + 1]);if (cs[temp]||!temp)continue;cs[temp] = true;ans++;}cout << ans << endl;}return 0;}


原创粉丝点击