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 题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报 思路:这题数据范围很大,直接搞超时+超内存,需要离散化: 离散化简单的来说就是只取我们需要 ...
随机推荐
- DB2 的create or update方法
通过merge方法实现的: MERGE INTO IFEBASE.STYLE AS MT USING (SELECT :scenario AS SCENARIO_ID, :style AS SHAPE ...
- HTTP状态码一览表(HTTP Status Code)
copy from:http://www.189works.com/article-43064-1.html 1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态代码. 代码 说明 100 ( ...
- ubuntu 点点滴滴
pptpd http://linux.cn/article-3376-1.html 命令行升级ubuntu版本 do-release-upgrade -d 寻找最新的稳定版本,加上-d参数则包括不稳 ...
- 10个免费开源的JS音乐播放器插件
点这里 音乐播放器在网页设计中有时候会用到,比如一些时尚类.音乐或影视类等项目,但这些 网页播放器 插件比较少见,所以这里为大家整理一个集合,也许会有用到的时候. 下面整理的播放器有些是支持自适应的, ...
- 传说中的WCF(8):玩转消息协定
Message翻译成中文,相信各位不陌生,是啊,就是消息,在WCF中也有消息这玩意儿,不知道你怎么去理解它.反正俺的理解,就像我们互发短信一个道理,通讯的双方就是服务器与客户端,说白了吧,就是二者之间 ...
- poj 2762(强连通+判断链)
题目链接:http://poj.org/problem?id=2762 思路:首先当然是要缩点建新图,由于题目要求是从u->v或从v->u连通,显然是要求单连通了,也就是要求一条长链了,最 ...
- Spark源码分析(二)-SparkContext创建
原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3872785.html SparkContext是应用启动时创建的Spark上下文对象,是一个重要的入口 ...
- lintcode:装最多水的容器
装最多水的容器 给定 n 个非负整数 a1, a2, ..., an, 每个数代表了坐标中的一个点 (i, ai).画 n 条垂直线,使得 i 垂直线的两个端点分别为(i, ai)和(i, 0).找到 ...
- JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-001Mapping basic properties(@Basic、@Access、access="noop"、@Formula、@ColumnTransformer、@Generated、 @ColumnDefaul、@Temporal、@Enumerated)
一.简介 在JPA中,默认所有属性都会persist,属性要属于以下3种情况,Hibernate在启动时会报错 1.java基本类型或包装类 2.有注解 @Embedded 3.有实现java.io. ...
- apimonitor
1.简介 由于Andorid更新很快,较之Droidbox这种通过hook系统动态分析APK行为的方法,APIMonitor这种通过在APK包中注入监控代码(监控API调用然后保存为日志)然后重打包A ...