https://cn.vjudge.net/problem/POJ-2528
一个十分经典的题,想用自己的法子离散化,硬是wa了40多发还没能过,整个人都要自闭了,贼难受。最后无奈用了别人的方法,好不爽。。。
我在此主要讲一下离散化的方法(当然是别人的方法啦),此题完整的代码放在最后!!!!
1.先把每条线段的单独存下来,同时把每个端点的值存在另一个数组里,在此把图放上
for(int i = 1; i <= n; ++ i)
{
cin >> li[i] >> ri[i];
x[cnt++] = li[i];
x[cnt++] = ri[i];
}
2.来一发排序,sort即可,然后处理一下相邻数据的差超过1的情况。先解释一下为什么,线段树是以点的形式存储了线段,所以难免会有局限,比如区间[1, 4]和[5, 6], 在线段数里面其实是相连接的,也就是说中间没有空隙(注意!!!),按照普通的离散化,两个不连续的数离散化之后会是连续的数,比如[1, 4], [2, 8], [7, 10]这三条线段,离散后:[1, 3], [2, 5], [4, 6], 然后算算离散前后的结果,一个是3, 一个是2,所以说就要把相差超过1的数据的特点体现出来,使得其之间有空隙。方法就是在这两个数中间再加一个数。就是x[i - 1]++这个操作了,最后再来发sort就ok了
sort(x + 1, x + cnt);
int m = cnt;
for(int i = 2; i < cnt; ++ i)
{
if(x[i] - x[i - 1] > 1)
{
x[m++] = x[i - 1]++;
}
}
sort(x + 1, x + m);
3.然后把数组中重复的元素去掉,因为接下来我们要用二分查找来确定每条线段的标号,去重才能保证标号唯一。
int top = 2;
y[1] = x[1];
for(int i = 2; i < m; ++ i)
{
if(x[i] != x[i - 1])
{
y[top++] = x[i];
}
}
4.下来就是通过二分查找把每条线段离散后的范围和标号对应起来,进行区间更新。
for(int i = 1; i <= n; ++ i)
{
int L = Bin(1, top - 1, li[i]);
int R = Bin(1, top - 1, ri[i]);
Update(L, R, i, 1, top - 1, 1);
}
另外附上二分查找的函数
inline int Bin(int l, int r, int x)
{
int m;
while(l < r)
{
m = (l + r) / 2;
if(y[m] == x)
return m;
else if(y[m] > x)
r = m - 1;
else
l = m + 1;
}
return l;
}
最后再查询一波就好了
下面上完整代码:
再解释一下我的线段树,我用-1代表此区间没有颜色或者不是纯色的情况(反正这两种情况都差不多,不能直接统计)
尽我努力,希望能对你有帮助。。发现有错误也欢迎积极评论^_^
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10003;
int Tree[8 * N], li[4 * N], ri[4 * N], x[4 * N], y[4 * N], sum;
bool vis[4 * N];
inline int Bin(int l, int r, int x)
{
int m;
while(l < r)
{
m = (l + r) / 2;
if(y[m] == x)
return m;
else if(y[m] > x)
r = m - 1;
else
l = m + 1;
}
return l;
}
void Update(int L, int R, int op, int l, int r, int rt)
{
if(l >= L && r <= R)
{
Tree[rt] = op;
return ;
}
if(Tree[rt] != -1)
{
int ans = Tree[rt];
Tree[rt*2] = ans;
Tree[rt*2+1] = ans;
Tree[rt] = -1;
}
int m = (l + r) >> 1;
if(m >= L)
Update(L, R, op, l, m, rt << 1);
if(m < R)
Update(L, R, op, m + 1, r, rt << 1 | 1);
}
void Query(int l, int r, int rt)
{
if(Tree[rt] != -1)
{
if(!vis[Tree[rt]])
{
vis[Tree[rt]] = true;
sum++;
}
return ;
}
if(l == r)
return ;
int m = (l + r) / 2;
Query(l, m, rt << 1);
Query(m + 1, r, rt << 1 | 1);
}
int main()
{
int t, n;
cin >> t;
while(t--)
{
cin >> n;
memset(vis, false, sizeof(vis));
memset(Tree, -1, sizeof(Tree));
int cnt = 1;
for(int i = 1; i <= n; ++ i)
{
cin >> li[i] >> ri[i];
x[cnt++] = li[i];
x[cnt++] = ri[i];
}
sort(x + 1, x + cnt);
int m = cnt;
for(int i = 2; i < cnt; ++ i)
{
if(x[i] - x[i - 1] > 1)
{
x[m++] = x[i - 1]++;
}
}
sort(x + 1, x + m);
int top = 2;
y[1] = x[1];
for(int i = 2; i < m; ++ i)
{
if(x[i] != x[i - 1])
{
y[top++] = x[i];
}
}
for(int i = 1; i <= n; ++ i)
{
int L = Bin(1, top - 1, li[i]);
int R = Bin(1, top - 1, ri[i]);
Update(L, R, i, 1, top - 1, 1);
}
sum = 0;
Query(1, top - 1, 1);
cout << sum << endl;
}
return 0;
}