题目大意
给出N条线段的x坐标,以及两个y坐标,要求你求出线段之间两两相互可见的三元组数量
题解
先对线段按x坐标升序排序,按顺序进行处理,每次先查询操作,如果当前线段i与其之前的某个线段可见,那么在它们之间建立一条边(用容器来存储),表示它们两相互可见,然后再进行更新操作。处理完之后就是统计了,直接暴力即可。。。还有就是容器记得初始化。。。我被坑了。。。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; #define MAXN 8005 #define lson l,m,s<<1 #define rson m+1,r,s<<1|1 typedef struct { int x; int y1; int y2; } NODE; NODE seg[MAXN]; int setv[MAXN<<3],hash[MAXN]; vector<int> g[MAXN]; bool cmp(NODE a,NODE b) { return a.x<b.x; } void PushDown(int s) { if(setv[s]) { setv[s<<1]=setv[s<<1|1]=setv[s]; setv[s]=0; } } void update(int ql,int qr,int d,int l,int r,int s) { if(ql<=l&&r<=qr) { setv[s]=d; return; } PushDown(s); int m=(l+r)>>1; if(ql<=m) update(ql,qr,d,lson); if(qr>m) update(ql,qr,d,rson); } void query(int ql,int qr,int d,int l,int r,int s) { if(setv[s]) { if(hash[setv[s]]!=d) { g[d].push_back(setv[s]); hash[setv[s]]=d; } return; } if(l==r) return; PushDown(s); int m=(l+r)>>1; if(ql<=m) query(ql,qr,d,lson); if(qr>m) query(ql,qr,d,rson); } int main(void) { int T,n; scanf("%d",&T); while(T--) { int y1,y2; scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d%d%d",&y1,&y2,&seg[i].x); seg[i].y1=y1*2; seg[i].y2=y2*2; g[i].clear(); } memset(setv,0,sizeof(setv)); memset(hash,0,sizeof(hash)); sort(seg+1,seg+n+1,cmp); for(int i=1; i<=n; i++) { query(seg[i].y1,seg[i].y2,i,0,MAXN<<1,1); update(seg[i].y1,seg[i].y2,i,0,MAXN<<1,1); } int ans=0,a,b,t,temp,c; for(int i=1; i<=n; i++) { t=g[i].size(); for(int j=0; j<t-1; j++) for(int k=j+1; k<t; k++) { a=g[i][j]; b=g[i][k]; if(a<b) { temp=a; a=b; b=temp; } c=g[a].size(); for(int p=0; p<c; p++) if(g[a][p]==b) { ans++; break; } } } printf("%d\n",ans); } return 0; }