您的位置:首页 > 其它

pku2528(线段树加离散化)

2011-05-01 13:15 288 查看
悲剧呀,这道题目搞了那么久,原来是离散化的方法出现问题了,悲剧,实在悲剧

线段树 + 离散化
今天做了这道题目的时候, 也算是明白了 离散化 的基本
意思,因为 题目的 数据范围很大 , 1- 10000000,直接线段树的话, 先不说
内存会不会爆, 这么大的范围估计也是 TLE了.
仔细读题, 可以看到 1<= N <= 10000, 也就是说 最多只有 10000个点, 如果
每个点都不同, 那么最多也只有 20000 个数据, 那么离散后的 范围就相当小;

离散化 的大概思路 : 比如说给你一组 数据 1 4 1000 100000, 如果直接
开线段, 显然是浪费, 那么我们只要 进行 映射 :
1 1
4 2
1000 3
100000 4
接下来 我们只要对 1 2 3 4 建立线段树就行了 只需要
[1,4]的区间

嘿嘿,这个是刚写的代码,简洁了许多,也快了一点

#include<iostream>
#include<map>
#include<set>
#define MAXN 10010
using namespace std;
struct node
{
int c;
}p[MAXN*8];
int left1[MAXN],right1[MAXN],n,m,num;
bool col[MAXN];
map<int,int> map1;
map<int,int>::iterator it;
void bulid(int k,int s,int t)
{
if(t==s) return ;
p[k].c=0;
int kl=k<<1,kr=kl+1,mid=(s+t)>>1;
bulid(kl,s,mid);
bulid(kr,mid+1,t);
}
void insert(int k,int s,int t,int l,int r,int e)
{
if(l>t||r<s) return ;
if(l<=s&&t<=r)
{
p[k].c=e;
return ;
}
int kl=k<<1,kr=kl+1,mid=(s+t)>>1;
if(p[k].c!=-1)
{
p[kl].c=p[kr].c=p[k].c;
p[k].c=-1;
}
insert(kl,s,mid,l,r,e);
insert(kr,mid+1,t,l,r,e);
}
void query(int k,int s,int t)
{
if(p[k].c!=-1)
{
if(!col[p[k].c])
{
num++;
col[p[k].c]=true;
}
return ;
}
int kl=k<<1,kr=kl+1,mid=(s+t)>>1;
query(kl,s,mid);
query(kr,mid+1,t);
}

int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
map1.clear();
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d %d",&left1[i],&right1[i]);
map1[left1[i]]=10;
map1[right1[i]]=10;
}
it=map1.begin();
int i=1;
for(;it!=map1.end();i++,it++)
it->second=i;
n =i;
bulid(1,1,n);
for(int i=0;i<m;i++)
insert(1,1,n,map1[left1[i]],map1[right1[i]],i+1);
num=0;
memset(col,false,sizeof(col));
col[0]=true;
query(1,1,n);
printf("%d\n",num);
}
return 0;
}


#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
#define MAX_N  20010
struct In
{
int left;
int right;
}str[MAX_N];
struct Node
{
int l;
int r;
int col;
}p[8*MAX_N];
set<int> my_set;
map<int,int> mp;
map<int,int>::iterator beg,end1;
int cmp( const void *a , const void *b ){
return *(int *)a-*(int *)b;
}
void bulid(int k,int s,int t)
{
int kr,kl,mid;
p[k].l=s;p[k].r=t;p[k].col=0;
if(s==t)
return ;
mid=(s+t)>>1;kl=k<<1;kr=kl+1;
bulid(kl,s,mid);
bulid(kr,mid+1,t);
}
void insert(int k,int s,int t,int v)
{
int kr,kl,mid;
if(s==p[k].l&&t==p[k].r)
{
p[k].col=v;
}
else {
mid=(p[k].l+p[k].r)>>1;kl=k<<1;kr=kl+1;
if(p[k].col!=-1)
{
p[kl].col=p[kr].col=p[k].col;
p[k].col=-1;
}
if(t<=mid) insert(kl,s,t,v);
else if(s>mid) insert(kr,s,t,v);
else {
insert(kl,s,mid,v);
insert(kr,mid+1,t,v);
}
}
}
void query(int k,int s,int t)
{
if(p[k].col!=-1)
{
my_set.insert(p[k].col);//将颜色插入set中,自动去重
return ;
}
int mid=(p[k].r+p[k].l)>>1,kl=k<<1,kr=kl+1;
if(t<=mid) query(kl,s,t) ;
else if(s>mid) query(kr,s,t);
else {
query(kl,s,mid);query(kr,mid+1,t);
}
}
int main()
{
int i,j,cas,n,m,num;
scanf("%d",&cas);
bulid(1,1,MAX_N);
while(cas--)
{
my_set.clear();
mp.clear();
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d %d",&str[i].left,&str[i].right);
mp[str[i].left] = 10; mp[str[i].right] = 10;
}
beg = mp.begin(), end1 = mp.end();
insert(1,1,2*n,0);
//因为map 已经自动排序了,所以直接从 1 --> N 开始标记, 离散化
for ( int i = 1;beg != end1; ++ beg, ++ i ) {
beg->second = i;
}
//因为线段树已经建立好了, 所以没必要每次都重建一次, 只要插入一条
//覆盖所有区间的 底板 就行了
for ( int i = 1; i <= n; ++ i ) {
//用离散后的标记 插入 线段
insert ( 1,mp[str[i].left], mp[str[i].right], i );
}
query(1,1,2*n);
num=my_set.size();//返回集合中元素个数
if(*my_set.begin()==0)
num--;
printf("%d\n",num);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: