解题思路:
一共有1e7块砖如果每个叶子节点都代表一块瓷砖,那么线段树会导致MLE,即单位区间的数目太多。而且建树复杂度O(m),查询复杂度为 nlogm (n是海报数目m是瓷砖数目)。
可是最多有1e4张海报所以最多有2e4个端点,而这些端点最多能把墙分成2e4+1段,对这些段进行编号做离散化处理,用sort()进行排序,如果相邻编号加一,如果不相邻编号加二。
对编好号的每一段进行建树并做好标记,标记表示这一段是否被覆盖过,然后从后往前贴海报如果海报所处的段中有瓷砖没有被覆盖就说明它是可见的
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 struct pos 7 { 8 int l,r; 9 }; 10 pos p[10010]; 11 int n; 12 int x[20010]; 13 int hash[10000010]; 14 struct node 15 { 16 int l,r; 17 node *pl,*pr; 18 bool flag; 19 }; 20 node t[800000]; 21 int tcount=0; 22 void build(node *proot,int l,int r) 23 { 24 proot->l=l; 25 proot->r=r; 26 proot->flag=0; 27 if(l==r) return; 28 tcount++; 29 proot->pl=t+tcount; 30 tcount++; 31 proot->pr=t+tcount; 32 build(proot->pl,l,(l+r)/2); 33 build(proot->pr,(l+r)/2+1,r); 34 } 35 36 bool post(node *proot,int l,int r) 37 { 38 if(proot->flag) 39 return 0; 40 if(proot->l==l&&proot->r==r) 41 { 42 proot->flag=1; 43 return 1; 44 } 45 bool b; 46 if(r<=(proot->l+proot->r)/2) 47 b=post(proot->pl,l,r); 48 else if(l>(proot->l+proot->r)/2) 49 b=post(proot->pr,l,r); 50 else 51 { 52 bool b1,b2; 53 b1=post(proot->pl,l,(proot->l+proot->r)/2); 54 b2=post(proot->pr,(proot->l+proot->r)/2+1,r); 55 b=b1||b2; 56 } 57 if(proot->pl->flag&&proot->pr->flag)//更新 58 proot->flag=1; 59 return b; 60 } 61 62 int main() 63 { 64 int c; 65 scanf("%d",&c); 66 while(c--) 67 { 68 int n; 69 scanf("%d",&n); 70 int ncount=0; 71 for(int i=0;i<n;++i) 72 { 73 scanf("%d%d",&p[i].l,&p[i].r); 74 x[ncount++]=p[i].l; 75 x[ncount++]=p[i].r; 76 } 77 sort(x,x+ncount);//排序后离散化 78 ncount=unique(x,x+ncount) - x; 79 int no=1; 80 for(int i=0;i<ncount;++i) 81 { 82 hash[x[i]]=no; 83 if(i<ncount-1) 84 { 85 if(x[i+1]-x[i]==1) 86 ++no; 87 else 88 no+=2; 89 } 90 } 91 build(t,1,no); 92 int nSum = 0; 93 for(int i=n-1;i>=0;--i) 94 if(post(t,hash[p[i].l],hash[p[i].r])) 95 nSum++; 96 printf("%d ",nSum); 97 } 98 return 0; 99 }