POJ 2528 (线段树 离散化) Mayor's posters
离散化其实就是把所有端点放在一起,然后排序去个重就好了。
比如说去重以后的端点个数为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的更多相关文章
- Mayor's posters POJ - 2528(线段树 + 离散化)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 74745 Accepted: 21574 ...
- poj 2528(线段树+离散化) 市长的海报
http://poj.org/problem?id=2528 题目大意是市长竞选要贴海报,给出墙的长度和依次张贴的海报的长度区间(参考题目给的图),问最后你能看见的海报有几张 就是有的先贴的海报可能会 ...
- poj2528(线段树+离散化)Mayor's posters
2016-08-15 题意:一面墙,往上面贴海报,后面贴的可以覆盖前面贴的.问最后能看见几种海报. 思路:可以理解成往墙上涂颜色,最后能看见几种颜色(下面就是以涂色来讲的).这面墙长度为1~1000 ...
- poj 2528 线段树+离散化
题意:在墙上贴一堆海报(只看横坐标,可以抽象成一线段),新海报可以覆盖旧海报.求最后能看到多少张海报 sol:线段树成段更新.铺第i张海报的时候更新sg[i].x~sg[i].y这一段为i. 然而坐标 ...
- poj 2528 线段树 离散化的小技巧
题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报思路:直接搞超时+超内存,需要离散化.离散化简单的来说就是只取我们需要的值来 用,比如说区间[1000,2000],[1990,2012] ...
- Mayor's posters POJ - 2528 线段树(离散化处理大数?)
题意:输入t组数据,输入n代表有n块广告牌,按照顺序贴上去,输入左边和右边到达的地方,问贴完以后还有多少块广告牌可以看到(因为有的被完全覆盖了). 思路:很明显就是线段树更改区间,不过这个区间的跨度有 ...
- Mayor's posters POJ - 2528 线段树区间覆盖
//线段树区间覆盖 #include<cstdio> #include<cstring> #include<iostream> #include<algori ...
- poj 2528 线段树区间修改+离散化
Mayor's posters POJ 2528 传送门 线段树区间修改加离散化 #include <cstdio> #include <iostream> #include ...
- 线段树---poj2528 Mayor’s posters【成段替换|离散化】
poj2528 Mayor's posters 题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报 思路:这题数据范围很大,直接搞超时+超内存,需要离散化: 离散化简单的来说就是只取我们需要 ...
随机推荐
- 【高可用HA】Apache (1) —— Mac下安装Apache Httpd到自定义路径(非/etc/apache2)
Mac下安装Apache Httpd httpd版本: httpd-2.4.17 参考来源: Tomcat Clustering - A Step By Step Guide Apache HTTP ...
- 驱动笔记 - file_operations
#include <linux/fs.h> struct file_operations { struct module *owner; loff_t (*llseek) (struct ...
- Sqli-labs less 28a
Less-28a 本关与28基本一致,只是过滤条件少了几个. http://127.0.0.1/sqllib/Less-28a/?id=100%27)unIon%0bsElect%0b1,@@base ...
- iOSpush过后返回多级界面
有导航控制器push过后pop可以反回上一个界面,然而我们需要返回多级界面有下面两种方法 调用API - (NSArray *)popToViewController:(UIViewControlle ...
- Android开发者应该深入学习的10个开源应用项目
Android 开发带来新一轮热潮让很多移动开发者都投入到这个浪潮中去了,创造了许许多多相当优秀的应用.其中也有许许多多的开发者提供了应用开源项目,贡献出他们的 智慧和创造力.学习开源代码是掌握技术的 ...
- servlet 项目
1.Servlet基础类,必须继承HttpServlet package com.fan; import java.io.IOException; import java.io.PrintWriter ...
- lintcode: 最小调整代价
题目 最小调整代价 给一个整数数组,调整每个数的大小,使得相邻的两个数的差小于一个给定的整数target,调整每个数的代价为调整前后的差的绝对值,求调整代价之和最小是多少. 样例 对于数组,最小的调整 ...
- hdu 4664 Triangulation(题意已在讨论版中说明)
题意: 给定n个平面(平面之间相互独立),每个平面上有一些点,并且构成凸集,C和D轮流选一个平面连接两个点画线段,并保证线段之间除了端点之外没有其它交点,当平面上出现一个完整的三角形之后此平面就不能继 ...
- 分析函数(Analytic Functions)
在OLAP这类系统或者DW这类数据库中,作为某份报表的数据源,我们常常需要在某个存储过程中编写复杂的运算代码来汇总数据.分析函数便具备这样的能力,引用多行的数据值来进行多层面的聚合运算,在数据子集中进 ...
- jdk、apache-ant结合yuicompressor配置的CSS与JS合并压缩工具
前序:网上很多css与js合并打包工具,其中最流行的就是ant结合yui-compressor,鉴于学习与工作需要今天就学习了一下这种方式,供大家学习交流. 步骤:1.安装jdk,并配置其变量环境:有 ...