(本人本题完成于2016-7-23)
题目大意:有一面很长(10000000节)的墙,要在上面贴N张海报,对于第i张海报,它将会覆盖墙面的第Li~Ri节。刚开始墙面是空的,求最后还有多少张海报是可见的(即未被其他海报完全覆盖的)。
以下是本人代码(貌似有瑕疵,可过官方数据,有待学习):
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
int d,n,a[200010]={0},q[200010]={0},v[200010]={0},tot,ans;
struct node
{
int l,r;
int n; //n表示该区间最后被第n张海报完全覆盖,当n为0时表示不能确定
}seg[600010];
bool cmp(int a,int b)
{
return a<b;
}
void buildtree(int no,int l,int r)
{
int mid=(l+r)/2;
seg[no].l=l;seg[no].r=r;seg[no].n=0;
if (l!=r)
{
buildtree(2*no,l,mid);
buildtree(2*no+1,mid+1,r);
}
}
void insert(int no,int s,int t,int i)
{
int mid=(seg[no].l+seg[no].r)/2;
if (a[seg[no].l]>=s&&a[seg[no].r]<=t)
{
seg[no].n=i;
return;
}
if (seg[no].n!=0)
{
seg[2*no].n=seg[2*no+1].n=seg[no].n;
seg[no].n=0;
}
if (s<=a[mid]) insert(2*no,s,t,i);
if (t>a[mid]) insert(2*no+1,s,t,i);
if (seg[2*no].n==seg[2*no+1].n) seg[no].n=seg[2*no].n;
else seg[no].n=0;
}
void query(int no)
{
if (seg[no].n!=0)
{
v[seg[no].n]=1;
return;
}
if (seg[no].l!=seg[no].r)
{
query(2*no);
query(2*no+1);
}
}
int main()
{
scanf("%d",&d);
for(int t=1;t<=d;t++)
{
memset(a,0,sizeof(a));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a[2*i-1],&a[2*i]);
q[2*i-1]=a[2*i-1];q[2*i]=a[2*i];
}
sort(a+1,a+2*n+1,cmp);
tot=0;
for(int i=1;i<=2*n;i++) if (a[tot]!=a[i]) {tot++;a[tot]=a[i];} //离散化
buildtree(1,1,tot);
for(int i=1;i<=n;i++)
insert(1,q[2*i-1],q[2*i],i);
memset(v,0,sizeof(v));
query(1);
ans=0;
for(int i=1;i<=n;i++) if (v[i]) ans++;
printf("%d
",ans);
}
return 0;
}