题意:贴广告,每个广告会占用一定的空间。后面的广告会覆盖前面的广告。问最后能看见的广告的数目
思路:以前这一题是用线段树做的,昨天zyc想到了一个用并查集写的方法,发现挺不错的,思想就是把已经被覆盖的区间所有点的父节点都变为左端点
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxN 40010
int ll[maxN],rr[maxN],fa[maxN],vist[maxN];
struct node{
int v,id;
bool f;
}po[2*maxN];
int cmp(node a,node b)
{
return a.v<b.v;
}
int query(int x)
{
if(fa[x]==x)return x;
return fa[x]=query(fa[x]);
}
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<=4*n;i++)
fa[i]=i;
memset(vist,0,sizeof(vist));
for(int i=0;i<2*n;i+=2){
scanf("%d%d",&po[i].v,&po[i+1].v);
po[i].f=true,po[i+1].f=false;
po[i].id=i/2,po[i+1].id=i/2;
}
sort(po,po+2*n,cmp);
int temp=-1,num=-1;
for(int i=0;i<2*n;i++)
{
if(po[i].v>temp+1)
num++;
if(po[i].v!=temp)
temp=po[i].v,num++;
if(po[i].f)
ll[po[i].id]=num;
else
rr[po[i].id]=num;
}
int cnt=0;
for(int i=n-1;i>=0;i--)
{
int u=query(ll[i]),v=query(rr[i]),flag=0;
if(!vist[u])vist[u]=1,flag=1;
if(u!=v){
while(v!=u){
if(!vist[v])vist[v]=1,flag=1;
fa[v]=u;
v=query(--v);
}
}
cnt+=flag;
}
printf("%d\n",cnt);
}
}