http://poj.org/problem?id=2528
这题一定要写个题解。Orz。
不信看图,五月多做过一次,一直RE。现如今来做,仍然RE多发。
题意:在墙壁上贴广告,广告的版面有大有小,并且贴广告有先后之分,后面贴的广告会覆盖前面的广告,求解最后能看到的广告面。
本题数据太大,要用到离散化,意思是将区间范围很大的数据集映射到较小的数据集。
离散化的步骤:
- 读取一对区间(x,y),用一个结构体(这里用arr)来存储这些点:arr[i].st =x,arr[i].ed=y;同时用另外一个离散的数组has来存储这些点,has[t++]=x,has[t++]=y;
- 把has数组sort一遍
- 把has数组unique(去重)一遍
int tt=unique(has,has+t)-has; 接下来更新线段树的时候,每个值通过二分得到:
int xx= lower_bound(has,has+tt,arr[i].st)
int yy= lower_bound(has,has+tt,arr[i].ed)
update(xx,yy);然后就没有然后了 ==
只不过这题的不同的是,题目给的数字代表的是一个单位长度,而不是具体的一个点,普通的离散化会造成错误。所以在区间长度大于1的时候,往往在区间多加一个点。我省掉了这个步骤,我是在不管是否大于1,区间都在左右端点分别再加点。
这题让我RE的不是数组开大开小的问题,是一个query懒人操作没有处理好的问题。
错错更健康,以后不再错就好 ==
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mset(x,y) memset(x,y,sizeof(x))
#define lson l,mid,i<<1
#define rson mid+1,r,i<<1|1
using namespace std;
const int N = 10000 +10;
int ans;
struct Node
{
int st,ed;
}arr[N];//记录区间的起点和终点
bool vis[N];
int has[N*4],tr[N*16];//注意数组范围,一定要开这么大
void built(int l,int r,int i)
{
tr[i]=0;
if(l==r) return;
int mid=(l+r)>>1;
built(lson);
built(rson);
return;
}
void pushdown(int i)
{
tr[i<<1] = tr[i<<1|1] = tr[i];
tr[i] = 0;
return;
}
void update(int l,int r,int i,int a,int b,int x)
{
if(l>=a&&r<=b)
{
tr[i] = x;
return;
}
if(tr[i]) pushdown(i);
int mid=(l+r)>>1;
if(mid>=a) update(lson,a,b,x);
if(mid<b) update(rson,a,b,x);
return;
}
void query(int l,int r,int i,int a,int b)
{
if(l>=a && r<=b &&tr[i]!=0)
{
if(vis[tr[i]]) ans++,vis[tr[i]]=false;
return;
}
if(l==r) return;//RE多发的关键处,Orz!!!
if(tr[i]) pushdown(i);
int mid= (l+r)>>1;
if(mid>=a) query(lson,a,b);
if(mid<b) query(rson,a,b);
return;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
mset(has,0);
int t=0;
for(int i=0;i<n;i++)
{
scanf("%d%d",&arr[i].st,&arr[i].ed);
has[t++]=arr[i].st;
has[t++]=arr[i].st+1;//奇妙的地方
has[t++]=arr[i].ed;
has[t++]=arr[i].ed-1;//奇妙的地方
}
sort(has,has+t);
int tt=unique(has,has+t)-has;
built(1,tt,1);
mset(vis,true);
ans=0;
for(int i=0;i<n;i++)
{
int x = lower_bound(has,has+tt,arr[i].st) - has + 1;//数组是从0开始的,所以+1保证正数性
int y = lower_bound(has,has+tt,arr[i].ed) - has + 1;
update(1,tt,1,x,y,i+1);
}
query(1,tt,1,1,tt);
printf("%d\n",ans);
}
return 0;
}