离散化其实就是把所有端点放在一起,然后排序去个重就好了。

比如说去重以后的端点个数为m,那这m个点就构成m-1个小区间。然后给这m-1个小区间编号1~m-1,再用线段树来做就行了。

具体思路是,从最后一张的海报来判断,如果海报覆盖的区域有空白区域那么这张海报就是可见的。并及时更新线段树信息。

说一个我调了很久的才发现小错误,比如书2 2这样一个海报,如果你把这张海报的左右端点都记作2的话那就是个空区间了。

其实,这张海报覆盖的是第2块瓷砖。所以R++,2 3就表示第2块瓷砖的左右端点。

当然,如果不是我这个思路,就可能不会出现这个问题。

这个是跟着去年北大的ACM培训班上给的标程写的,指针满天飞,个人感觉代码不够简洁。

 //#define LOCAL
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std; int n;
struct CPost
{
int L, R;
}posters[ + ];
int x[ + ]; //海报的端点瓷砖编号
int hash[ + ];//hash[i]表示瓷砖i所处的离散化后的区间编号 struct CNode
{
int L, R;
bool bCovered; //区间[L, R]是否已经完全覆盖
CNode *pLeft, *pRight;
}Tree[];
int nNodeCount = ;
int Mid(CNode* pRoot)
{
return (pRoot->L + pRoot->R) / ;
}
void BuildTree(CNode *pRoot, int L, int R)
{
pRoot->L = L;
pRoot->R = R;
pRoot->bCovered = false;
if(L == R)
return;
++nNodeCount;
pRoot->pLeft = Tree + nNodeCount;
++nNodeCount;
pRoot->pRight = Tree + nNodeCount;
BuildTree(pRoot->pLeft, L, (L+R)/);
BuildTree(pRoot->pRight, (L+R)/+, R);
}
bool Post(CNode *pRoot, int L, int R)
{//插入一张覆盖区间[L, R]的海报,返回true则说明该区间是部分或者全部可见的
if(pRoot->bCovered)
return false;
if(pRoot->L == L && pRoot->R == R)
{
pRoot->bCovered = true;
return true;
}
bool bResult;
if(R <= Mid(pRoot))
bResult = Post(pRoot->pLeft, L, R);
else if(L >= Mid(pRoot) + )
bResult = Post(pRoot->pRight, L, R);
else
{
bool b1 = Post(pRoot->pLeft, L, Mid(pRoot));
bool b2 = Post(pRoot->pRight, Mid(pRoot) + , R);
bResult = b1 || b2;
}
//要更新的节点的覆盖情况
if(pRoot->pLeft->bCovered && pRoot->pRight->bCovered)
pRoot->bCovered = true;
return bResult;
} int main(void)
{
#ifdef LOCAL
freopen("2528in.txt", "r", stdin);
#endif
int t;
int i, j, k;
scanf("%d", &t);
int nCaseNo = ;
while(t--)
{
++nCaseNo;
scanf("%d", &n);
int nCount = ;
for(i = ; i < n; ++i)
{
scanf("%d%d", &posters[i].L, &posters[i].R);
x[nCount++] = posters[i].L;
x[nCount++] = posters[i].R;
}
sort(x, x + nCount);
nCount = unique(x, x + nCount) - x;//元素去重
//将下面离散化
int nIntervalNo = ;
for(i = ; i < nCount; ++i)
{
hash[x[i]] = nIntervalNo;
if(i < nCount - )
{
if(x[i + ] - x[i] == )
++nIntervalNo;
else
nIntervalNo += ;
}
} BuildTree(Tree, , nIntervalNo);
int nSum = ;
for(i = n - ; i >= ; --i)
{//从后往前遍历每个海报是否可见
if(Post(Tree, hash[posters[i].L], hash[posters[i].R]))
++nSum;
}
printf("%d\n", nSum);
}
return ;
}

代码君

自己改成数组的写法,感觉可读性要好很多。

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = + ;
int covered[maxn << ];
int n, m, L[maxn], R[maxn], x[maxn]; bool post(int o, int L, int R, int qL, int qR)
{
if(covered[o]) return false;
if(qL == L && qR == R) { covered[o] = true; return true; }
int M = (L + R) / ;
bool ok;
if(qR <= M) ok = post(o*, L, M, qL, qR);
else if(qL > M) ok = post(o*+, M+, R, qL, qR);
else
{
bool ok1 = post(o*, L, M, qL, M);
bool ok2 = post(o*+, M+, R, M+, qR);
ok = ok1 || ok2;
}
if(covered[o*] && covered[o*+]) covered[o] = true;
return ok;
} int main()
{
//freopen("in.txt", "r", stdin); int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = ; i < n; i++)
{
scanf("%d%d", &L[i], &R[i]);
R[i]++;
x[i*] = L[i]; x[i*+] = R[i];
}
sort(x, x + n * );
m = unique(x, x + n * ) - x; memset(covered, false, sizeof(covered));
int ans = ;
for(int i = n - ; i >= ; i--)
{
int qL = lower_bound(x, x + m, L[i]) - x + ;
int qR = lower_bound(x, x + m, R[i]) - x;
if(post(, , m, qL, qR)) ans++;
}
printf("%d\n", ans);
} return ;
}

代码君

还有一种方法就是正向模拟,用setv[o]来表示该节点被哪张海报覆盖,此时线段树的功能就是区间替换。

最后查询的时候就看这些节点被哪张海报覆盖,注意有的海报可能会覆盖多个节点,为了避免重复统计,可以用一个bool标记数组。

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = + ;
int setv[maxn << ];
bool is_cnt[maxn]; int L[maxn], R[maxn], x[maxn];
int n, m, qL, qR, v, ans; void pushdown(int o)
{
if(setv[o] >= )
{
setv[o*] = setv[o*+] = setv[o];
setv[o] = -;
}
} void update(int o, int L, int R)
{
if(qL <= L && qR >= R) { setv[o] = v; return; }
pushdown(o);
int M = (L + R) / ;
if(qL <= M) update(o*, L, M);
if(qR > M) update(o*+, M+, R);
} void query(int o, int L, int R)
{
if(setv[o] >= )
{
if(!is_cnt[setv[o]]) { ans++; is_cnt[setv[o]] = true; }
return;
}
if(L == R) return;
int M = (L + R) / ;
query(o*, L, M);
query(o*+, M+, R);
} int main()
{
//freopen("in.txt", "r", stdin); int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = ; i < n; i++)
{
scanf("%d%d", &L[i], &R[i]);
R[i]++;
x[i*] = L[i]; x[i*+] = R[i];
}
sort(x, x + n * );
m = unique(x, x + n * ) - x; memset(setv, -, sizeof(setv));
memset(is_cnt, false, sizeof(is_cnt)); for(int i = ; i < n; i++)
{
v = i;
qL = lower_bound(x, x + m, L[i]) - x + ;
qR = lower_bound(x, x + m, R[i]) - x;
update(, , m - );
}
ans = ;
query(, , m - );
printf("%d\n", ans);
} return ;
}

代码君

POJ 2528 (线段树 离散化) Mayor's posters的更多相关文章

  1. Mayor's posters POJ - 2528(线段树 + 离散化)

    Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 74745   Accepted: 21574 ...

  2. poj 2528(线段树+离散化) 市长的海报

    http://poj.org/problem?id=2528 题目大意是市长竞选要贴海报,给出墙的长度和依次张贴的海报的长度区间(参考题目给的图),问最后你能看见的海报有几张 就是有的先贴的海报可能会 ...

  3. poj2528(线段树+离散化)Mayor's posters

    2016-08-15 题意:一面墙,往上面贴海报,后面贴的可以覆盖前面贴的.问最后能看见几种海报. 思路:可以理解成往墙上涂颜色,最后能看见几种颜色(下面就是以涂色来讲的).这面墙长度为1~1000 ...

  4. poj 2528 线段树+离散化

    题意:在墙上贴一堆海报(只看横坐标,可以抽象成一线段),新海报可以覆盖旧海报.求最后能看到多少张海报 sol:线段树成段更新.铺第i张海报的时候更新sg[i].x~sg[i].y这一段为i. 然而坐标 ...

  5. poj 2528 线段树 离散化的小技巧

    题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报思路:直接搞超时+超内存,需要离散化.离散化简单的来说就是只取我们需要的值来 用,比如说区间[1000,2000],[1990,2012] ...

  6. Mayor's posters POJ - 2528 线段树(离散化处理大数?)

    题意:输入t组数据,输入n代表有n块广告牌,按照顺序贴上去,输入左边和右边到达的地方,问贴完以后还有多少块广告牌可以看到(因为有的被完全覆盖了). 思路:很明显就是线段树更改区间,不过这个区间的跨度有 ...

  7. Mayor's posters POJ - 2528 线段树区间覆盖

    //线段树区间覆盖 #include<cstdio> #include<cstring> #include<iostream> #include<algori ...

  8. poj 2528 线段树区间修改+离散化

    Mayor's posters POJ 2528 传送门 线段树区间修改加离散化 #include <cstdio> #include <iostream> #include ...

  9. 线段树---poj2528 Mayor’s posters【成段替换|离散化】

    poj2528 Mayor's posters 题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报 思路:这题数据范围很大,直接搞超时+超内存,需要离散化: 离散化简单的来说就是只取我们需要 ...

随机推荐

  1. Isomorphic JavaScript: The Future of Web Apps

    Isomorphic JavaScript: The Future of Web Apps At Airbnb, we’ve learned a lot over the past few years ...

  2. JS通过ajax动态读取xml文件内容

    http://www.sharejs.com/codes/javascript/8178 HTML文件代码如下 <!DOCTYPE html> <html> <head& ...

  3. javascript设计模式-迭代器模式(Iterator)

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. MySQL 操作表命令

    新建表: create table Itemcats (id int(11) not null auto_increment, primary key (id)) engine=MyISAM auto ...

  5. SEO优化的黑帽手法是否值得使用?

    PR劫持 可能很多人也会听到说,什么网站权重越高越好,这也就是后面越来越多人都对谷歌的PR的宣传看的很重,自建站的都追求PR值,权重越高代表这个网站越受信任. 比如一个新站PR值为0,一个老站PR为6 ...

  6. yum install 与 yum groupinstall 的区别

    原文:http://blog.51yip.com/linux/1171.html yum 提供二种安装软件的方式 1,yum install 它安装单个软件,以及这个软件的依赖关系 2,yum gro ...

  7. Fbric、Ansible、Docker、Chaos Monkey:DevOps工具的年中回顾

    Fbric.Ansible.Docker.Chaos Monkey:DevOps工具的年中回顾 [编者按]近日,Cyber Engineering Solutions Group 技术经理 Hasan ...

  8. JavaWeb-JDK下载安装

    JDK官方下载地址:http://www.oracle.com/index.html JDK下载: 64位的下64的 JDK安装:(这是32位的) JDK部署测试:(配置环境变量) JAVA_HOME ...

  9. .Net知识点总结(一)

    1.文件上传:Jquery.uploadify  它依赖于flash  舍去起上传   功能  改用SWFupload  他是第三方的插件 2.验证码激活的时候,邮箱开始是写死的,但是为了以后更改邮箱 ...

  10. 20款最受欢迎的HTML5游戏引擎收集

    在“最火HTML5 JavaScript游戏引擎”系列文章国外篇(一)中,我们盘点了当下备受开发者推崇的非国产HTML5和JavaScript游戏引擎.在各种2D小游戏逆袭的今天,用HTML5和Jav ...