链接;点击打开链接
求三条线段,两两可见。两条线段可见是有一条平行X的直线与这两条线段都有交点且在这两条线段之间,没有其他线段与这条平行线相交。题目给你线段的起点和终点,还有x轴坐标。以Y轴来建树,按X轴排序,先求出两两可见的线段,储存在容器里(省时),然后for暴力求出三条两两可见的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define N 20000
struct edge{
int y1,y2,x;
}s[N];
struct node{
int l;
int r;
int num;
}anode[2*N];
int vis[N];
vector<int>V[N];
void bulid(int l,int r,int n){
int mid;
mid=(l+r)>>1;
anode[n].l=l;
anode[n].r=r;
anode[n].num=0;
if(l==r)
return;
bulid(l,mid,2*n);
bulid(mid+1,r,2*n+1);
}
void upchild(int n){
if(anode[n].num){
anode[2*n].num=anode[2*n+1].num=anode[n].num;
anode[n].num=0;
}
}
void update(int l,int r,int c,int n){
if(l<=anode[n].l&&anode[n].r<=r){
anode[n].num=c;
return;
}
upchild(n);
int mid=(anode[n].l+anode[n].r)>>1;
if(l<=mid)
update(l,r,c,2*n);
if(r>mid)
update(l,r,c,2*n+1);
}
void query(int l,int r,int id,int n){
if(anode[n].num){
if(vis[anode[n].num]!=id){
V[anode[n].num].push_back(id);
vis[anode[n].num]=id;
}
return;
}
if(anode[n].l==anode[n].r) return;
upchild(n);
int mid=(anode[n].l+anode[n].r)>>1;
if(l<=mid)
query(l,r,id,2*n);
if(r>mid)
query(l,r,id,2*n+1);
}
int cmp(edge a,edge b){
return a.x<b.x;
}
int main(){
int t,n,y1,y2,x,i,j,k;
cin>>t;
while(t--){
cin>>n;
for(i=1;i<=n;i++){
scanf("%d %d %d",&s[i].y1,&s[i].y2,&s[i].x);
s[i].y1<<=1;s[i].y2<<=1;V[i].clear();
}
sort(s+1,s+1+n,cmp);
bulid(1,16000,1);
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++){
query(s[i].y1,s[i].y2,i,1);
update(s[i].y1,s[i].y2,i,1);
}
int ans=0;
for(i=1;i<=n;i++){
for(j=0;j<V[i].size();j++){
x=V[i][j];
for(k=0;k<V[i].size();k++){
for(int t=0;t<V[x].size();t++)
if(V[i][k]==V[x][t])
ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}