pku2528(线段树加离散化)

悲剧呀,这道题目搞了那么久,原来是离散化的方法出现问题了,悲剧,实在悲剧

线段树 +  离散化
   今天做了这道题目的时候,  也算是明白了 离散化 的基本
   意思,因为 题目的 数据范围很大 , 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;
}
posted @ 2011-05-01 13:15  枕边梦  阅读(359)  评论(0编辑  收藏  举报