http://poj.org/problem?id=2528

题目大意是市长竞选要贴海报,给出墙的长度和依次张贴的海报的长度区间(参考题目给的图),问最后你能看见的海报有几张

就是有的先贴的海报可能会被后贴的海报完全盖住,那就看不见了

这里就非常抽象的区间更新,墙的长度为建立线段树的总区间,每贴一张海报代表将这个区间的颜色涂为相应的,每张海报的颜色当然

都不相同,求最后又多少种颜色就行,但这里还要用到基础的离散化

离散化是把无限空间中无限的个体映射到有限的空间中去,以此提高算法的时空效率。

简单点说,假设区间长度有一亿甚至跟多,但是区间里具体的值却最多只用到了一百万,且不说能否开那么大的数组,也造成了

内存的浪费,所以用离散化来节省不必要的浪费

举这个题目的样例来说(前三个)

如果只是改变区间1 7    2 6    8 10的颜色,那么剩下的数字并没有用到

那么我们将这些数字排序,x[1]=1 x[2]=2 x[3]=6 x[4]=7 x[5]=8 x[6]=10

但是如果每个相邻的差值大于1的时候要插入一个数(就插入x[i]-1好了),

(如果不插的话

 假设三张海报为:1 10   1 4   6 10

离散化时 x[1] = 1   x[2]=4  X[3]=6   X[4]=10
第一张海报时:墙的1~4被染为1;
第二张海报时:墙的1~2被染为2,3~4仍为1;
第三张海报时:墙的3~4被染为3,1~2仍为2。
最终,第一张海报就显示被完全覆盖了,然后输出2,但是正确答案明显是3)

插入后新的排序为x[1]=1 x[2]=2 x[3]=5 x[4]=6 x[5]=7 x[6]=8 x[7]=9 x[8]=10

然后以这个新的长度为8的数组区间建树就好

 

code

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 struct point {
 7     int l,r;
 8     int mark,sum;
 9 };
10 point tree[10001*4*4],num[10001*4];
11 int ans,res[10001*4],visit[10001*4];
12 void build(int i,int left,int right)
13 {
14     tree[i].l=left,tree[i].r=right;
15     tree[i].mark=tree[i].sum=0;
16     if (left==right) return ;
17     int mid=(left+right)/2;
18     build(i*2,left,mid);
19     build(i*2+1,mid+1,right);
20 }
21 void update(int i,int left,int right,int val)
22 {
23     if (left<=tree[i].l&&tree[i].r<=right){tree[i].mark=tree[i].sum=val;return ;}
24     if (tree[i].mark)
25     {
26         tree[i*2].mark=tree[i*2+1].mark=tree[i].mark;
27         tree[i*2].sum=tree[i*2+1].sum=tree[i].mark;
28         tree[i].mark=0;
29     }
30     int mid=(tree[i].r+tree[i].l)/2;
31     if (left>mid) update(i*2+1,left,right,val);
32     else if (right<=mid) update(i*2,left,right,val);
33     else
34     {
35         update(i*2,left,mid,val);
36         update(i*2+1,mid+1,right,val);
37     }
38 }
39 int find(int i)
40 {
41     if (tree[i].l==tree[i].r)
42     {
43         if (!visit[tree[i].sum])
44         {
45            visit[tree[i].sum]=1;
46            ++ans;
47         }
48         return ans;
49     }
50     if (tree[i].mark)
51     {
52         tree[i*2].mark=tree[i*2+1].mark=tree[i].mark;
53         tree[i*2].sum=tree[i*2+1].sum=tree[i].mark;
54         tree[i].mark=0;
55     }
56     find(i*2);
57     find(i*2+1);
58 }
59 int main()
60 {
61     int t,i,n,tn,tn1,powr,powl;
62     scanf("%d",&t);
63 
64         if (t==0) return 0;
65         while (t--)
66         {
67             res[0]=0;
68             scanf("%d",&n);
69             for (i=1;i<=n;i++)
70             {
71                scanf("%d %d",&num[i].l,&num[i].r);
72                if (num[i].l>num[i].r) swap(num[i].l,num[i].r);
73                res[++res[0]]=num[i].l;
74                res[++res[0]]=num[i].r;
75             }
76             sort(res+1,res+res[0]+1);//离散化
77             tn1=tn=unique(res+1,res+res[0]+1)-res;
78             for (i=2;i<tn;i++)//插入数
79                if (res[i]-res[i-1]>1)
80                   res[tn1++]=res[i]-1;
81             res[0]=tn1-1;
82             sort(res+1,res+res[0]+1);
83             build(1,1,res[0]);//以新的区间建树
84             for (i=1;i<=n;i++)
85             {
86                 powl=lower_bound(res+1,res+1+res[0],num[i].l)-res;
87                 powr=lower_bound(res+1,res+1+res[0],num[i].r)-res;
88                 update(1,powl,powr,i);
89             }
90             ans=0;
91             memset(visit,0,sizeof(visit));
92             visit[0]=1;
93             printf("%d\n",find(1));
94         }
95 
96     return 0;
97 }

 

posted on 2015-08-12 17:40  蜘蛛侦探  阅读(1057)  评论(1编辑  收藏  举报