题目大意:给出n条垂直于x轴的线段的数据y1,y2,x,求出有几个三条线段一组的三元组并且他们兩兩能相见的。 思路:对y轴建树,将x排序,然后按顺序边询问边擦入,用mark[i][j]表示j往左可以看到i。最后用一个三重循环计算答案。 但是注意:0,4,1 和 0,2,2 和 3,4,2这三条线段覆盖的结果是区间0~4通过线段树查找可见线段是两条,其实是3条(2~3可见另一条) 这里可以将y轴×2表示。这样就能解决这样的问题 0 1 2 3 4 2~3被覆盖 所以乘2解决
#include#include #include using namespace std;#define MAXN 16005struct node{ int l,r,w;}x[MAXN<<3];struct abc{ int y1,y2,x;}z[MAXN];bool m1[MAXN/2][MAXN/2];bool cmp(abc a,abc b){ return a.x >1; Build(l,mid,a<<1); Build(mid+1,r,a<<1|1);}void Insert(int l,int r,int i,int a){ if(z[i].y1<=l&&r<=z[i].y2) { x[a].w=i; return ; } if(l==r) return ; if(x[a].w!=-1) push_down(a); int mid=(l+r)>>1; if(z[i].y1<=mid) Insert(l,mid,i,a<<1); if(z[i].y2>mid) Insert(mid+1,r,i,a<<1|1);}void Ques(int l,int r,int i,int a){ if(x[a].w!=-1) { m1[x[a].w][i]=1; return ; } if(l==r) return ; if(x[a].w!=-1) push_down(a); int mid=(l+r)>>1; if(z[i].y1<=mid) Ques(l,mid,i,a<<1); if(z[i].y2>mid) Ques(mid+1,r,i,a<<1|1);}int main(){ int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); memset(m1,0,sizeof(m1)); for(int i=1;i<=n;i++) { scanf("%d%d%d",&z[i].y1,&z[i].y2,&z[i].x); z[i].y1<<=1; z[i].y2<<=1; } Build(0,MAXN,1); sort(z+1,z+n+1,cmp); for(int i=1;i<=n;i++) { Ques(0,MAXN,i,1); Insert(0,MAXN,i,1); } int ans=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(m1[i][j]) for(int k=1;k<=n;k++) if(m1[i][k]&&m1[j][k]) ans++; printf("%d\n",ans); } return 0;}