题目链接

题意

用不同颜色的线段覆盖数轴,问最终数轴上有多少种颜色?

注:只有最上面的线段能够被看到;即,如果有一条线段被其他的线段给完全覆盖住,则这个颜色是看不到的。

法一:线段树

按题意按顺序模拟即可。

法二:线段树+离线

将整个过程倒过来看待,如果要加进去的线段所在的区域已经完全被覆盖,那么这条线段就没有贡献,否则就有\(1\)的贡献。

法三:并查集+离线

离线处理思想同上。

用\(fa[\ ]\)数组记录某个元素左边距其最近的没有被覆盖的点的坐标。那么对于当前覆盖的线段\([l,r]\),只要\(find(r)\lt l\),就意味着当前这一段已经完全被覆盖,所以贡献为\(0\).

并查集的思想类似BZOJ 3211 花神游历各国

注意点

这道题的坑点在于:离散化

如果普通地进行离散化,考虑

3
1 10
1 4
6 10

会被离散化成

3
1 4
1 2
3 4

本来有三种颜色,处理过之后就只有两种颜色了。

问题在于:顺序的连续并不代表位置的连续。

处理时在中间插入额外的点即可。

Code

Ver. 1

#include <stdio.h>
#include <algorithm>
#include <string.h>
#define lson rt<<1
#define rson rt<<1|1
#define maxn 100010
using namespace std;
typedef long long LL;
int a[maxn], l[maxn], r[maxn], b[maxn], ans;
bool vis[maxn];
struct tree { int l, r, c, flag; }tr[maxn*4];
void build(int rt, int l, int r) {
tr[rt].l = l, tr[rt].r = r; tr[rt].flag = tr[rt].c = 0;
if (l==r) return;
int mid = l+r >> 1;
build(lson, l, mid), build(rson, mid+1, r);
}
void push_down(int rt) {
if (tr[rt].flag) {
tr[lson].flag = tr[rson].flag
= tr[lson].c = tr[rson].c = tr[rt].flag;
tr[rt].flag = 0;
}
}
void push_up(int rt) {
tr[rt].c = tr[lson].c == tr[rson].c ? tr[lson].c : 0;
}
void modify(int rt, int l, int r, int c) {
if (tr[rt].l == l && tr[rt].r == r) {
tr[rt].c = tr[rt].flag = c;
return;
}
push_down(rt);
int mid = tr[rt].l + tr[rt].r >> 1;
if (r <= mid) modify(lson, l, r, c);
else if (l > mid) modify(rson, l, r, c);
else modify(lson, l, mid, c), modify(rson, mid+1, r, c);
push_up(rt);
}
void query(int rt) {
if (tr[rt].l == tr[rt].r || tr[rt].c) {
if (!vis[tr[rt].c] && tr[rt].c) ++ans, vis[tr[rt].c] = true;
return;
}
push_down(rt);
query(lson); query(rson);
}
void work() {
int n;
scanf("%d", &n);
int tot=0;
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &l[i], &r[i]);
a[++tot] = l[i], a[++tot] = r[i];
}
sort(a+1,a+tot+1);
tot = unique(a+1,a+tot+1)-a-1; b[1] = a[1]; int cnt = 1;
for (int i = 2; i <= tot; ++i) {
if (a[i]-a[i-1] == 1) b[++cnt] = a[i];
else b[++cnt] = a[i-1] + 1, b[++cnt] = a[i];
} build(1,1,cnt);
for (int i = 1; i <= n; ++i) {
int pl = lower_bound(b+1, b+1+cnt, l[i]) - b,
pr = lower_bound(b+1, b+1+cnt, r[i]) - b;
modify(1, pl, pr, i);
} ans = 0; memset(vis, 0, sizeof(vis));
query(1);
printf("%d\n", ans);
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}

Ver. 2

#include <stdio.h>
#include <algorithm>
#include <map>
#define lson rt<<1
#define rson rt<<1|1
#define maxn 100010
using namespace std;
typedef long long LL;
int a[maxn], l[maxn], r[maxn], b[maxn];
struct tree { int l, r; bool cov, flag; }tr[maxn*4];
map<int,int> mp;
void build(int rt, int l, int r) {
tr[rt].l = l, tr[rt].r = r; tr[rt].cov = 0; tr[rt].flag = 0;
if (l==r) return;
int mid = l+r >> 1;
build(lson, l, mid), build(rson, mid+1, r);
}
void push_down(int rt) {
if (tr[rt].flag) {
tr[lson].cov = tr[rson].cov = tr[lson].flag = tr[rson].flag = 1;
tr[rt].flag = 0;
}
}
void push_up(int rt) {
tr[rt].cov = tr[lson].cov && tr[rson].cov;
}
bool insert(int rt, int l, int r) {
if (tr[rt].l==l && tr[rt].r==r) {
if (tr[rt].cov) return true;
tr[rt].cov = tr[rt].flag = true;
return false;
}
push_down(rt);
int mid = tr[rt].l + tr[rt].r >> 1;
bool ret;
if (r <= mid) ret = insert(lson, l, r);
else if (l > mid) ret = insert(rson, l, r);
else {
// 注意!这里不能直接写成 ret = insert(lson, l, mid) & ans2 = insert(rson, mid+1, r);
// 因为根据短路原理,如果前面的为假,后面的就直接不做了!
bool ans1 = insert(lson, l, mid), ans2 = insert(rson, mid+1, r);
ret = ans1&ans2;
}
push_up(rt);
return ret;
}
void work() {
int n;
scanf("%d", &n);
int tot=0;
for (int i = 0; i < n; ++i) {
scanf("%d%d", &l[i], &r[i]);
a[++tot] = l[i], a[++tot] = r[i];
}
sort(a+1,a+tot+1);
tot = unique(a+1,a+tot+1)-a-1; b[1] = a[1]; int cnt = 1;
for (int i = 2; i <= tot; ++i) {
if (a[i]-a[i-1] == 1) b[++cnt] = a[i];
else b[++cnt] = a[i-1] + 1, b[++cnt] = a[i];
} build(1,1,cnt);
int ans=0;
for (int i = n-1; i >= 0; --i) {
int pl = lower_bound(b+1, b+1+cnt, l[i]) - b,
pr = lower_bound(b+1, b+1+cnt, r[i]) - b;
if (!insert(1, pl, pr)) ++ans;
}
printf("%d\n", ans);
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}

Ver. 3

#include <stdio.h>
#include <algorithm>
#include <map>
#define maxn 100010
using namespace std;
typedef long long LL;
int a[maxn], l[maxn], r[maxn], fa[maxn], b[maxn];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
map<int,int> mp;
void work() {
int n;
scanf("%d", &n);
int tot=0;
for (int i = 0; i < n; ++i) {
scanf("%d%d", &l[i], &r[i]);
a[++tot] = l[i], a[++tot] = r[i];
}
sort(a+1,a+tot+1);
tot = unique(a+1,a+tot+1)-a-1; b[1] = a[1]; int cnt = 1;
for (int i = 2; i <= tot; ++i) {
if (a[i]-a[i-1] == 1) b[++cnt] = a[i];
else b[++cnt] = a[i-1] + 1, b[++cnt] = a[i];
}
for (int i=0; i<=cnt; ++i) fa[i] = i; int ans=0;
for (int i = n-1; i >= 0; --i) {
int pl = lower_bound(b+1, b+1+cnt, l[i]) - b,
pr = lower_bound(b+1, b+1+cnt, r[i]) - b;
if (find(pr)<pl) continue;
++ans;
for (int j = find(pr); j >= pl; j = find(j-1)) {
fa[find(j)] = find(pl-1);
}
}
printf("%d\n", ans);
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}

poj 2528 Mayor's posters 线段树 || 并查集 离线处理的更多相关文章

  1. POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化)

    POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化) 题意分析 贴海报,新的海报能覆盖在旧的海报上面,最后贴完了,求问能看见几张海报. 最多有10000张海报,海报 ...

  2. poj 2528 Mayor's posters 线段树+离散化技巧

    poj 2528 Mayor's posters 题目链接: http://poj.org/problem?id=2528 思路: 线段树+离散化技巧(这里的离散化需要注意一下啊,题目数据弱看不出来) ...

  3. poj 2528 Mayor's posters 线段树区间更新

    Mayor's posters Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=2528 Descript ...

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

    Mayor's posters 转载自:http://blog.csdn.net/winddreams/article/details/38443761 [题目链接]Mayor's posters [ ...

  5. poj 2528 Mayor's posters 线段树+离散化 || hihocode #1079 离散化

    Mayor's posters Description The citizens of Bytetown, AB, could not stand that the candidates in the ...

  6. POJ 2528 Mayor's posters (线段树)

    题目链接:http://poj.org/problem?id=2528 题目大意:有一个很上的面板, 往上面贴海报, 问最后最多有多少个海报没有被完全覆盖 解题思路:将贴海报倒着想, 对于每一张海报只 ...

  7. poj 2528 Mayor's posters(线段树)

    题目:http://poj.org/problem?id=2528 题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的, 但是必定是单位宽度的整数 ...

  8. POJ 2528 Mayor's posters (线段树区间更新+离散化)

    题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值 ...

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

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

随机推荐

  1. 从Mixin到hooks,谈谈对React16.7.0-alpha中即将引入的hooks的理解

      为了实现分离业务逻辑代码,实现组件内部相关业务逻辑的复用,在React的迭代中针对类组件中的代码复用依次发布了Mixin.HOC.Render props等几个方案.此外,针对函数组件,在Reac ...

  2. python编写定时执行脚本

    前几天在抓博客园文章,打算每天抓10条最新的,所以就在脚本中加了定时让它在每天凌晨四点中时执行,但是昨天发现,报错了: 显示是远程主机强制关闭了一个链接, 原因是:mysql数据库默认当连续8小时不对 ...

  3. POJ:2492-Bug's Life(二分图的判定)

    Bug's Life Time Limit: 10000MS Memory Limit: 65536K Description Background Professor Hopper is resea ...

  4. Linux命令之---mv

    命令简介 mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files) 命令格式 mv [选项] 源文件或目录 目标文件或目录 命令参数 -b 若需覆盖文件,则覆 ...

  5. Linux命令之---diff

    命令介绍 diff命令可以酌行比较纯文本文件内的内容,并输出文件的差异. 命令格式 diff [option] [file1] [file2] 举例子 1)比较俩文本文件 [root@king ~]# ...

  6. 《鸟哥的Linux私房菜》学习笔记(8)——bash脚本编程之变量

    一.变量命名                                                             1.只能包含字母.数字和下划线,并且不能以数字开头,    2.不 ...

  7. Codeforces 35E Parade 扫描线

    题意: 给出\(n\)个底边在\(x\)轴上的矩形,求外面的轮廓线顶点. 分析: 将每个矩形拆成两个事件:\(\\\{ l, y, + \\\}\)和\(\\\{ r, y, - \\\}\)分别表示 ...

  8. IT帮2019年2月线下活动【定义工作,解读自我】之站桩练习

    2019年2月IT帮线下活动[定义工作,解读自我] 昨天的活动收获很大,全面的总结周老师会另写一篇来帮助大家回顾.我想说一下其中最打动我的一句话:“只有你能决定你有多优秀!” “工作中把自己当成企业家 ...

  9. MySQL基础6-分组查询

    1.分组函数 需求20:查询所有商品平均零售价SELECT AVG(salePrice) FROM product 需求21:查询商品总记录数SELECT COUNT(id) count FROM p ...

  10. Eclipse配置Maven工具

    1.Maven安装,下载Maven二进行制文件: http://maven.apache.org/download.cgi 下载后解压,然后设置maven的bin目录到系统环境变量Path中,在cmd ...