%%%
//感觉博主对于离散的解释很好,很感谢。
%%%
//博主解释了一下本题离散的特殊性,感谢
如三张海报为:1~10 1~4 6~10
离散化时 X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 6, X[ 4 ] = 10
第一张海报时:墙的1~4被染为1;
第二张海报时:墙的1~2被染为2
3~4仍为1;
第三张海报时:墙的3~4被染为3,
1~2仍为2。
最终,第一张海报就显示被完全覆盖了,于是输出2,但实际上明显不是这样,正确输出为3。
新的离散方法为:在相差大于1的数间加一个数,例如在上面1 4 6 10中间加5(算法中实际上1,4之间,6,10之间都新增了数的)
X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 5, X[ 4 ] = 6, X[ 5 ] = 10
这样之后,第一次是1,5被染成1;第二次1,2被染成2;第三次4,5被染成3
最终,[1,2]为2,3为1,[4,5]为3,于是输出正确结果3。
离散化时 X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 6, X[ 4 ] = 10
第一张海报时:墙的1~4被染为1;
第二张海报时:墙的1~2被染为2
3~4仍为1;
第三张海报时:墙的3~4被染为3,
1~2仍为2。
最终,第一张海报就显示被完全覆盖了,于是输出2,但实际上明显不是这样,正确输出为3。
新的离散方法为:在相差大于1的数间加一个数,例如在上面1 4 6 10中间加5(算法中实际上1,4之间,6,10之间都新增了数的)
X[ 1 ] = 1, X[ 2 ] = 4, X[ 3 ] = 5, X[ 4 ] = 6, X[ 5 ] = 10
这样之后,第一次是[1,5]被染成1;第二次[1,2]被染成2;第三次[4,5]被染成3
最终,[1,2]为2,3为1,[4,5]为3,于是输出正确结果3。
这里说一下对于代码的理解
if (left>mid)
update(i * 2 + 1, left, right, val);
else if (right <= mid)
update(i * 2, left, right, val);
else
{
update(i * 2, left, mid, val);
update(i * 2 + 1, mid + 1, right, val);
}
这里目标区间的左端点大于mid,则需要向右节点进行更新(因为右节点的区间左端点更大)
同理当(right<=mid)或者(left<=mid <=right)时也是如此
代码是之前从一位dalao那看完后,模仿的,但是之前一直没有写这道题目的总结,忘了收藏dalao的博客,很抱歉.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct point {
int l, r;
int mark, sum;
};
point tree[10001 * 4 * 4], num[10001 * 4];
int ans, res[10001 * 4], vis[10001 * 4];
void build(int i, int left, int right)
{
tree[i].l = left, tree[i].r = right;
tree[i].mark = tree[i].sum = 0;
if (left == right) return;
int mid = (left + right) / 2;
build(i * 2, left, mid);
build(i * 2 + 1, mid + 1, right);
}
void update(int i, int left, int right, int val)
{
if (left <= tree[i].l&&tree[i].r <= right) {
tree[i].mark = tree[i].sum = val; return;
}
//等同于lazy
if (tree[i].mark)
{
tree[i * 2].mark = tree[i * 2 + 1].mark = tree[i].mark;
tree[i * 2].sum = tree[i * 2 + 1].sum = tree[i].mark;
tree[i].mark = 0;
}
int mid = (tree[i].r + tree[i].l) / 2;
//此时的mid取决于i所以要判断mid>left,right<= 的情况。
if (left>mid) update(i * 2 + 1, left, right, val);
else if (right <= mid) update(i * 2, left, right, val);
else
{
update(i * 2, left, mid, val);
update(i * 2 + 1, mid + 1, right, val);
}
}
//查找
int find(int i)
{
if (tree[i].l == tree[i].r)
{
if (!vis[tree[i].sum])//没被计算过
{
vis[tree[i].sum] = 1;
++ans;
}
return ans;
}
//等同于lazy,即延迟更新
if (tree[i].mark)
{
tree[i * 2].mark = tree[i * 2 + 1].mark = tree[i].mark;
tree[i * 2].sum = tree[i * 2 + 1].sum = tree[i].mark;
tree[i].mark = 0;
}
find(i * 2);
find(i * 2 + 1);
}
int main()
{
int t, i, n, tn, tn1, powr, powl;
scanf("%d", &t);
if (t == 0)
return 0;
while (t--)
{
res[0] = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
scanf("%d %d", &num[i].l, &num[i].r);
if (num[i].l>num[i].r) swap(num[i].l, num[i].r);
res[++res[0]] = num[i].l;
res[++res[0]] = num[i].r;
}
sort(res + 1, res + res[0] + 1);
//离散化
tn1 = tn = unique(res + 1, res + res[0] + 1) - res;//去重后得到范围
for (i = 2; i<tn; i++)//插入数
if (res[i] - res[i - 1]>1)
res[tn1++] = res[i] - 1;
//每个相邻的差值大于1的时候要插入一个数(就插入x[i]-1好了)
res[0] = tn1 - 1;//插入后的数据个数
sort(res + 1, res + res[0] + 1);
build(1, 1, res[0]);//以新的区间(映射后的范围)建树
for (i = 1; i <= n; i++)
{
powl = lower_bound(res + 1, res + 1 + res[0], num[i].l) - res;
powr = lower_bound(res + 1, res + 1 + res[0], num[i].r) - res;
//映射后所在位置,进行数据的更新
update(1, powl, powr, i);
}
ans = 0;
memset(vis, 0, sizeof(vis));
vis[0] = 1;
printf("%d\n", find(1));
}
return 0;
}