pku2528 线段树(离散化)

Mayor's posters

又一道线段树!对于数据量比较小,区间长度比较大的,一般都需要离散化来实现。

类别:求区间里有多少种不同的覆盖。

解题思路:先读入数据,将每个区间的两个端点都记为两个点,排序,将相同的点去掉。开始初始化线段树,每次更新,就是新插入个区间,二分查找,找到两个端点对应下标,对他们进行区间修改,剩下处理部分与pku2777相似,就不多说了,而且2777那题可以不用位运算,也可以像这题一样,用一个数组标记,判断用了哪几种cover值。

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#include < stdio.h >
#include
< string .h >
#include
< stdlib.h >
#define NN 10000

struct node{
int l, r, cover;
}st[NN
* 16 ];
int index, f[ 2 * NN + 4 ], seg[NN][ 2 ];
char mark[NN * 2 + 4 ];

int cmp( const void * a, const void * b){
int * aa = ( int * )a;
int * bb = ( int * )b;

return * aa - * bb;
}

int Find( int x){
int low = 0 ;
int hig = index - 1 ;
do {
int mid = (low + hig) >> 1 ;
if (x == f[mid]){
return mid;
}
else if (x > f[mid]){
low
= mid + 1 ;
}
else {
hig
= mid - 1 ;
}
}
while (low <= hig);
}

void Init( int l, int r, int id){
st[id].l
= l;
st[id].r
= r;
st[id].cover
= 0 ;

if (r - l <= 1 ){
return ;
}

int mid = (l + r) >> 1 ;

Init(l, mid, id
* 2 );
Init(mid, r, id
* 2 + 1 );
}

void Update( int l, int r, int key, int id){
if (st[id].l == l && st[id].r == r){
st[id].cover
= key;
return ;
}

if (st[id].cover > 0 ){
st[id
* 2 ].cover = st[id].cover;
st[id
* 2 + 1 ].cover = st[id].cover;
st[id].cover
= 0 ;
}

int mid = (st[id].l + st[id].r) >> 1 ;

if (r <= mid){
Update(l, r, key, id
* 2 );
}
else if (l >= mid){
Update(l, r, key, id
* 2 + 1 );
}
else {
Update(l, mid, key, id
* 2 );
Update(mid, r, key, id
* 2 + 1 );
}
}

void Search( int l, int r, int id){
if (st[id].cover > 0 ){
mark[st[id].cover]
= 1 ;
return ;
}

int mid = (st[id].l + st[id].r) >> 1 ;

if (r <= mid){
Search(l, r, id
* 2 );
}
else if (l >= mid){
Search(l, r, id
* 2 + 1 );
}
else {
Search(l, mid, id
* 2 );
Search(mid, r, id
* 2 + 1 );
}
}
int main()
{
int T, n, i, t, l, r, ans;
scanf(
" %d " , & T);
while (T -- ){
scanf(
" %d " , & n);
index
= 0 ;
for (i = 0 ; i < n; i ++ ){
scanf(
" %d%d " , & seg[i][ 0 ], & seg[i][ 1 ]);
f[index
++ ] = seg[i][ 0 ];
f[index
++ ] = seg[i][ 1 ];
}

t
= 1 ;
qsort(f, index,
sizeof (f[ 0 ]), cmp);
for (i = 1 ; i < index; i ++ ){
if (f[i] != f[i - 1 ]){
f[t
++ ] = f[i];
}
}
index
= t;

Init(
0 , index, 1 );
for (i = 0 ; i < n; i ++ ){
l
= Find(seg[i][ 0 ]);
r
= Find(seg[i][ 1 ]);
Update(l, r
+ 1 , i + 1 , 1 );
}
memset(mark,
0 , sizeof (mark));
Search(
0 , index, 1 );
ans
= 0 ;
for (i = 1 ; i <= n; i ++ ){
if (mark[i]){
ans
++ ;
}
}
printf(
" %d\n " , ans);
}
// system("pause");
return 0 ;
}

 

转载于:https://www.cnblogs.com/ylfdrib/archive/2010/07/18/1780282.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值