题意:
给你8000条平行Y轴且互不相交的线段,若两条线段之间存在一条只与该两条线段相交的水平线段,则称这两条线段相互可见
求有多少个三条线段两两之间能够相互可见
给你一个整数T,表示T组测试数据
给你一个整数n,表示n条线段
下面n行每行三个整数yi,yii,x ,表示一条线段 0 <= yi' < yi'' <= 8 000, 0 <= xi <= 8 000
方法一:
现将线段按x排序,然后用线段树区间更新求当前线段覆盖了前面哪些线段,因为线段树中存的是点,所以我们要将区间倍增
另外,在更新时,应先查询这个区间会有哪些线段与当前线段可见,然后再将该区间更新为线段i
PS: 我以为暴力枚举会超时的。。。 没想到最后只花了一秒多。。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 8005
using namespace std;
struct edge
{
int yi, yii, x;
bool operator < (const edge &a)const
{
return x< a.x;
}
}edge[maxn];
bool g[maxn][maxn];
struct node
{
int l, r, num;
}a[4*2*maxn];
void Build(int l, int r, int n)
{
a[n].l= l;
a[n].r= r;
a[n].num= 0;
if(a[n].l== a[n].r)
return;
int mid=(a[n].l + a[n].r)>> 1;
Build(l ,mid, 2*n);
Build(mid+1, r, 2*n+1);
}
void Query(int l, int r, int n, int num) //查询区间[L,R]能和线段num相互看见的有哪些线段
{
if(a[n].num)
{
g[a[n].num][num]= g[num][a[n].num]= true;
return;
}
if(a[n].l== a[n].r)
return;
int mid= (a[n].l+ a[n].r)>> 1;
if(r<= mid)
Query(l ,r, 2*n, num);
else if(l> mid)
Query(l, r, 2*n+1, num);
else
{
Query(l, mid, 2*n, num);
Query(mid+1, r, 2*n+1, num);
}
}
void update(int l, int r, int n, int num)//将区间[L,R]变成线段num
{
if(a[n].l==l && a[n].r== r)
{
a[n].num= num;
return;
}
if(a[n].num)
{
a[2*n+1].num= a[2*n].num= a[n].num;
a[n].num= 0;
}
int mid= (a[n].l+ a[n].r)>> 1;
if(r<= mid)
update(l ,r, 2*n, num);
else if(l> mid)
update(l, r, 2*n+1, num);
else
{
update(l, mid, 2*n, num);
update(mid+1, r, 2*n+1, num);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i= 1; i<= n; i++)
scanf("%d %d %d",&edge[i].yi,&edge[i].yii, &edge[i].x);
sort(edge+1, edge+n+1);
Build(0, 16000, 1);
memset(g, false, sizeof(g));
for(int i= 1; i<= n; i++)
{
Query(2*edge[i].yi, 2*edge[i].yii, 1, i);
update(2*edge[i].yi, 2*edge[i].yii, 1, i);
}
int ans= 0;
for(int i= 1; i<= n; i++)
for(int j= i+1; j<= n; j++)
if(g[i][j])
{
for(int k= j+1; k<= n; k++)
if(g[i][k] && g[j][k])
ans++;
}
printf("%d\n",ans);
}
return 0;
}
方法二:
与方法一不同之处在于,先将区间[L,R]更新为线段num,再用区间[L,R]往下查询哪些线段会与之相互可见
PS: 我最开始就是这样写的。。 不过某渣实在是太弱,代码写惨了。。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 8005
struct edge
{
int yi, yii, x;
bool operator < (const edge &a)const
{
return x < a.x;
}
}edge[8005];
struct node
{
int l, r;
int sz;
}a[4*2*maxn];
bool g[maxn][maxn];
void Build(int l, int r, int n)
{
a[n].l= l;
a[n].r= r;
a[n].sz= 0;
if(a[n].l== a[n].r)
return ;
int mid= (a[n].l + a[n].r)>> 1;
Build(l, mid, 2*n);
Build(mid+1, r, 2*n+1);
}
void pushdown(int n)
{
if(a[n].sz)
{
a[2*n].sz= a[2*n+1].sz= a[n].sz;
a[n].sz= 0;
}
}
void Query(int l, int r, int n, int num)
{
if(a[n].sz)
{
g[a[n].sz][num]= g[num][a[n].sz]= true;
return;
}
if(a[n].l== a[n].r)
return;
int mid= (a[n].l + a[n].r)/2 ;
if(r<= mid)
Query(l, r, 2*n, num);
else if(l> mid)
Query(l, r, 2*n+1, num);
else
{
Query(l, mid, 2*n, num);
Query(mid+1, r, 2*n+1, num);
}
}
void update(int l, int r, int n, int num)
{
if(a[n].l== l && a[n].r== r)
{
if(a[n].sz)
{
g[a[n].sz][num]= g[num][a[n].sz]= true;
a[n].sz= num;
}
else
{
Query(l, r, n, num);
a[n].sz= num;
}
return;
}
pushdown(n);
int mid= (a[n].l + a[n].r)/2 ;
if(r<= mid)
update(l, r, 2*n, num);
else if(l> mid)
update(l, r, 2*n+1, num);
else
{
update(l, mid, 2*n, num);
update(mid+1, r, 2*n+1, num);
}
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i= 1; i<= n; i++)
scanf("%d %d %d", &edge[i].yi, &edge[i].yii, &edge[i].x);
sort(edge+1, edge+n+1);
Build(0, 16000, 1);
memset(g, false, sizeof(g));
for(int i= 1; i<= n; i++)
update(2*edge[i].yi, 2*edge[i].yii, 1, i);
int ans= 0;
for(int i= 1; i<= n; i++)
for(int j= i+1; j<= n; j++)
if(g[i][j])
for(int k= j+1; k<= n; k++)
if(g[i][k]&& g[j][k])
ans++;
printf("%d\n",ans);
}
return 0;
}