Description
Input
Output
Sample Input
1 5 0 4 4 0 3 1 3 4 2 0 2 2 0 2 3
Sample Output
1
【题意】给了你n条线段,问在这n条线段中,最多能组成多少个相互可见的三角形,所谓相互可见,就是用一条直线连接这条线段和那条线段的顶点(这里的线段是垂直于x轴的),那么这道题怎么做呢?
【解题思路】刚看懂这个题的题意,马上想到了一个相似的问题,贴海报,那么解决这道题的最优策略是怎样的呢?当然是对输入的一堆线段按照高度排序之后,做成线段树就好了,线段树需要增加一个标记记录覆盖当前区间的线段编号,这里为col。做成线段树之后,由于这里有区间更新,要考虑Push_Down,接下来就是手动推一下样例,但是怎么推怎么不对(-><-),看了一下别人的blog,发现了一个新问题,例如0,4,1 和 0,2,2 和 3,4,2。这个数据就能说明问题了,如果不乘以2 那么 第二条 和 第三条就把 x=2 这一段堵死了,其实还有2-3这一个线段的。解决了这个问题,本题就完美解决了。实现细节见我的AC代码。
【AC代码】#include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int nn = 8005; bool vis[nn][nn]; struct seg{ int l,r,h; friend bool operator<(const seg &a,const seg &b) { return a.h<b.h; } }seg[nn]; struct node{ int l,r,col; }Tree[nn<<3]; void Push_Down(int rt) { if(Tree[rt].col!=-1) { Tree[rt<<1].col=Tree[rt<<1|1].col=Tree[rt].col; Tree[rt].col=-1; } } void Build(int l,int r,int rt) { Tree[rt].l=l,Tree[rt].r=r,Tree[rt].col=-1; if(l==r)return ; int m = (l+r)>>1; Build(lson); Build(rson); } void Update(int L,int R,int val,int rt) { if(L<=Tree[rt].l&&Tree[rt].r<=R) { Tree[rt].col = val; return ; } Push_Down(rt); int m = (Tree[rt].l+Tree[rt].r)>>1; if(L<=m) Update(L,R,val,rt<<1); if(m<R) Update(L,R,val,rt<<1|1); } void query_ans(int L,int R,int val,int rt)//询问和当前线段可以相互可见的线段 { if(Tree[rt].col!=-1) { vis[Tree[rt].col][val] = true; return ; } if(Tree[rt].l==Tree[rt].r)return ; int m =(Tree[rt].l+Tree[rt].r)>>1; if(L<=m) query_ans(L,R,val,rt<<1); if(m<R) query_ans(L,R,val,rt<<1|1); } int main() { ios::sync_with_stdio();cin.tie(0); int T,n; scanf("%d",&T); while(T--) { cin>>n; for(int i=1; i<=n; i++) { scanf("%d%d%d",&seg[i].l,&seg[i].r,&seg[i].h); seg[i].l<<=1,seg[i].r<<=1; } sort(seg+1,seg+n+1); Build(1,nn*2,1); memset(vis,0,sizeof(vis)); for(int i=1; i<=n; i++) { query_ans(seg[i].l,seg[i].r,i,1); Update(seg[i].l,seg[i].r,i,1); } int ans = 0; for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(vis[i][j]) { for(int k=1; k<=n; k++) { if(vis[i][k]&&vis[j][k]) ans++; } } } } printf("%d\n",ans); } return 0; }