poj - 2528 Mayor's posters(线段树+离散化)
2015-08-10 17:18
232 查看
题意:在墙上贴海报,海报之间可以互相覆盖,问最后可以看见几张海报.
思路:这题数据范围很大,直接搞容易超时+超内存,需要离散化.
离散化简单来说就是只取我们需要用到的值来用,比如说区间[1000,2000],[1990,2012]
我们用不到[-inf,999][1001,1989],[1991,1999],[2001,2011][2013,+inf]这些值,
所以只需要1000,1990,2000,2012就够了,将其分别映射到0,1,2,3复杂度就会降下来.
所以离散化就是保存所有需要用到的值,排序后,分别映射到1-n,就可以降低复杂度.
但是这题每个数字其实表示一个单位长度(并非一个点),普通离散化会造成许多错误.
比如:
1-10 1-4 5-10
1-10 1-4 6-10
离散化后都是[1,4][1,2][3,4]
为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.
线段树功能:update:成段替换 query:简单hash
思路:这题数据范围很大,直接搞容易超时+超内存,需要离散化.
离散化简单来说就是只取我们需要用到的值来用,比如说区间[1000,2000],[1990,2012]
我们用不到[-inf,999][1001,1989],[1991,1999],[2001,2011][2013,+inf]这些值,
所以只需要1000,1990,2000,2012就够了,将其分别映射到0,1,2,3复杂度就会降下来.
所以离散化就是保存所有需要用到的值,排序后,分别映射到1-n,就可以降低复杂度.
但是这题每个数字其实表示一个单位长度(并非一个点),普通离散化会造成许多错误.
比如:
1-10 1-4 5-10
1-10 1-4 6-10
离散化后都是[1,4][1,2][3,4]
为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.
线段树功能:update:成段替换 query:简单hash
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn = 11111; bool hash[maxn]; int li[maxn],ri[maxn]; int x[maxn*3]; int col[maxn<<4]; int cnt; void pushDown(int rt) { if(col[rt]!=-1) { col[rt<<1]=col[rt<<1|1]=col[rt]; col[rt]=-1; } } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R) { col[rt]=c; return; } pushDown(rt); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(m<R) update(L,R,c,rson); } void query(int l,int r,int rt) { if(col[rt]!=-1) { if(!hash[col[rt]]) cnt++; hash[col[rt]]=true; return; } if(l==r) return; int m=(l+r)>>1; query(lson); query(rson); } int Bin(int key,int n,int x[]) { int l=0,r=n-1; while(l<=r) { int m=(l+r)>>1; if(x[m]==key) return m; if(x[m]<key) l=m+1; else r=m-1; } return -1; } int main() { //freopen("a.txt","r",stdin); int t,n; scanf("%d",&t); while(t--) { scanf("%d",&n); int nn=0; for(int i=0;i<n;i++) { scanf("%d%d",&li[i],&ri[i]); x[nn++]=li[i]; x[nn++]=ri[i]; } sort(x,x+nn); int m=1; for(int i=1;i<nn;i++) //去掉重复的 { if(x[i]!=x[i-1]) x[m++]=x[i]; } for(int i=m-1;i>0;i--) //如果间距大于1就插入任意一个数 { if(x[i]!=x[i-1]+1) x[m++]=x[i-1]+1; } sort(x,x+m); memset(col,-1,sizeof(col)); for(int i=0;i<n;i++) //二分查找左右边界在x中的位置 { int l=Bin(li[i],m,x); int r=Bin(ri[i],m,x); update(l,r,i,0,m,1);//用第i种颜色更新 } cnt=0; memset(hash,0,sizeof(hash)); query(0,m,1); printf("%d\n",cnt); } return 0; }
相关文章推荐
- LNMP的Nginx启动脚本和配置文件
- Struts2中Action由自己与由Spring管理的区别
- 高性能IO模型浅析
- 社会化海量数据采集爬虫框架搭建
- Android 实现形态各异的双向侧滑菜单 自定义控件来袭
- android消息处理机制
- 【POJ 2676】Sudoku
- 【产品体验】喵街&飞凡
- hdu 1151 Air Raid(二分图最小路径覆盖)
- HDU 1281 棋盘游戏
- HDOJ-2006-求奇数的乘积
- Burpsuite截获https数据包
- java IO流(File类)
- 知识图谱 资源
- 关于函数参数入栈的思考(函数调用约定,入栈顺序)
- 快的等哈慢的,要有团体意识——异步多任务等待之触发器模式
- ROS中的turtlebot包
- 在ibatis中使用oracle insert all 函数
- 登录表单
- 关于函数参数入栈的思考