链接:http://poj.org/problem?id=2528
题意:一面特别特别特别长的墙要贴相对非常短的海报,按给出顺序贴,问贴完后最后还能看见那几张海报。
思路:不能用最基本的线段树,因为墙实在太长了,会MLE。用离散化的思想。就是把所有海报的端点从小到大依次标记为1,2...M。(需要去重,所以不一定是2*N个点),其他的与基本线段树相同。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 10005
#define maxm
#define INF 1<<25
#define MAX 0x7fffffff
typedef long long ll;
using namespace std;
struct Line
{
int l,r;
int per;
int mid()
{
return (l+r)>>1;
}
}line[maxn*8];
int P[maxn][2],N[maxn*2],A[10000005];
int build_tree(int l,int r,int step)
{
line[step].l=l;
line[step].r=r;
line[step].per=0;
if(l==r)
return 0;
build_tree(l,line[step].mid(),step<<1);
build_tree(line[step].mid()+1,r,step<<1|1);
}
int update(int l,int r,int step)
{
if(line[step].per)
return 0;
if(line[step].l==l&&r==line[step].r)
{
line[step].per=1;
return 1;
}
int res=0;
if(line[step].mid()>=r)
res=update(l,r,step<<1);
else if(line[step].mid()<l)
res=update(l,r,step<<1|1);
else
{
res=update(l,line[step].mid(),step<<1)|update(line[step].mid()+1,r,step<<1|1);
}
if(line[step<<1].per&&line[step<<1|1].per)
line[step].per=1;
return res;
}
int init()
{
memset(P,0,sizeof(P));
memset(N,0,sizeof(N));
memset(A,0,sizeof(A));
memset(line,0,sizeof(line));
}
int main()
{
int tot,tt;
scanf("%d",&tot);
for(int ii=0;ii<tot;ii++)
{
init();
int j=0;
scanf("%d",&tt);
for(int i=0;i<tt;i++)
{
scanf("%d%d",&P[i][0],&P[i][1]);
N[j++]=P[i][0];
N[j++]=P[i][1];
}
sort(N,N+j);
j=unique(N,N+j)-N;//unique函数返回非重复数的最后一个的尾地址
for(int i=0;i<j;i++)
{
A[N[i]]=i;
}
build_tree(0,j-1,1);
int ans=0;
for(int i=tt-1;i>=0;i--)
{
if(update(A[P[i][0]],A[P[i][1]],1))
ans++;
}
printf("%d\n",ans);
}
}