大概题意:有一面很长的墙,按照输入顺序往上面贴海报(每张海报的宽度和墙都相同,所以输入数据给的只有海报的左端坐标和有段坐标)问最后可以看见几张海报(只看见一部分也算看见);
分析:观察数据范围1000W这么大的数字,直接做的话必然会爆内存和超时,所以要进行离散化(这是本人的做的第一道要使用离散化的题目,还好离散化的部分比较容易),海报的数字却只有10000,所以出现的数字(坐标)最多就是20000,我们可以吧所有出现的数字按从小到大标号,用标号的大小来判断数字的大小;由于即使离散化了数据任然很大,所以这里使用线段树;这里是成段更新的线段树,这里每个节点有三个属性(left、right、color)前两个没什么特殊的,主要说明一下color这个元素,表示海报的颜色,如果这个left-right之间这一条线段有颜色切唯一的话color才会有值,最后把树建好了之后再写一个DFS(这个DFS比较简短就不多说了)计算有多少种不同的颜色,看到这里应该就可以敲这道题了;
以下是我的AC代码:(水平较低,仅供参考)
/*
Problem: 2528 User: Burglar
Memory: 2236K Time: 63MS
Language: G++ Result: Accepted
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string.h>
#include <iostream>
#define MAXN 10005
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
using namespace std;
struct Node
{
int point;//记录数字
int num;//记录这个数字来自于哪一个输入数据
}line[MAXN<<3];//数组一定要记得开大些刚开始时4被结果WA了
struct Input_line
{
int l,r;
int color;
}input_line[MAXN];//输入
struct Tree
{
int left,right;
int color;
}tree[MAXN<<3];//树
int n,ans;
int judge[MAXN];
bool cmp(Node a,Node b)//用来对数字排序
{
return a.point<b.point;
}
void Build(int l,int r,int rt)//建树
{
tree[rt].left=l;
tree[rt].right=r;
tree[rt].color=0;
if(l==r) return;
int m=(l+r)>>1;
Build(lson);
Build(rson);
return;
}
void update(int color,int l,int r,int rt)
{
if(tree[rt].left==l&&tree[rt].right==r)//正好完全覆盖住
{
tree[rt].color=color;
return;
}
if(tree[rt].color!=0)
{
tree[rt<<1].color=tree[rt<<1|1].color=tree[rt].color;//吧这个根节点的颜色付给他的两个儿子,让后再归零
tree[rt].color=0;
}
if(l>=tree[rrt].left) update(color,l,r,rrt);//完全在右边
else if(r<=tree[lrt].right) update(color,l,r,lrt);//完全在左边
else//左右两边都有
{
update(color,l,tree[lrt].right,lrt);
update(color,tree[rrt].left,r,rrt);
}
return;
}
void DFS(int rt)//用递归的方式记录答案
{
if(tree[rt].color!=0)
{
if(!judge[tree[rt].color])
{
ans++;
judge[tree[rt].color]=1;
}
return;
}
else
{
DFS(rt<<1);
DFS(rt<<1|1);
}
return;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(line,0,sizeof(line));
memset(judge,0,sizeof(judge));
ans=0;
scanf("%d",&n);
for(int i=0;i<n;i++)//离散化的过程
{
scanf("%d%d",&input_line[i].l,&input_line[i].r);
input_line[i].color=i+1;
line[i<<1].point=input_line[i].l;
line[i<<1].num=-(i+1);//用复数表示左边,应为i从0开始如果不加一的话就不能通过正负来判断左边还是右边;
line[i<<1|1].point=input_line[i].r;
line[i<<1|1].num=(i+1);
}
sort(line,line+(n<<1),cmp);
int next_point=line[0].point;
int num_point=1;
for(int i=0;i<(n<<1);i++)
{
if(next_point!=line[i].point)
{
num_point++;
next_point=line[i].point;
}
if(line[i].num<0)
input_line[-line[i].num-1].l=num_point;
else
input_line[line[i].num-1].r=num_point;
}
Build(1,num_point,1);
for(int i=0;i<n;i++)
{
update(input_line[i].color,input_line[i].l,input_line[i].r,1);
}
DFS(1);
printf("%d\n",ans);
}
return 0;
}