YYHS-Super Big Stupid Cross(二分+扫描线+平衡树)
Posted I__am
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了YYHS-Super Big Stupid Cross(二分+扫描线+平衡树)相关的知识,希望对你有一定的参考价值。
题目描述
输入
输出
样例输入
样例输出
提示
题解
这道题可以暴力水过,正解是二分+扫描线+平衡树
网上看到的题解都是暴力的,这里写一下正解的算法
读入的时候我们先把横的和竖的线都找出来,并且存一下每条线的len和两端的位置(如果是横的就记录x1,x2,竖的就记录y1,y2)
然后我们二分答案,每次check的时候,把所有线段都减去2*二分的长度(因为两边都要减)并加到新数组里(横的归横的,竖的归竖的),这里我们还要多加一个id值,在之后能用到,如果某条线段的长度不够了,就不用把这条线加到数组里面了
这里我用th[]记录横的线,ts[]记录竖的线
加到数组中后,我们就开始扫描,扫描到横的线的左端就把这条线的y坐标加入到平衡树上(可以用c++的set),扫描到竖的线就查找lower_bound(这条线的下端点),判断一下找到的值是否<=这条线的上端点,如果扫到横的线的右端就把这条线的y坐标从平衡树上删去
因为坐标的范围很大,我们不能直接枚举坐标,所以我们可以按横的线的左端和右端分别排个序,用L[]和R[]存一下,每次用指针往后找就可以了,至于多加的id值,因为排过序,横的线的次序就打乱了,所以我们在加入到数组后直接用另一个数组把th[]存下来,这样每次查询id的时候就可以找到原来的th[].id了
说了那么多,来看看代码吧(可能会好懂一些)
1 #include<algorithm> 2 #include<cstdio> 3 #include<cstring> 4 #include<set> 5 #define N 100005 6 using namespace std; 7 int n,x1,x2,y1,y2,cnt1,cnt2,l,r,ans,nums,numh; 8 multiset<int> q; 9 typedef set<int>::iterator It; 10 struct node{ 11 int x,l,r,len; 12 }s[N],ts[N]; 13 struct Node{ 14 int y,l,r,len,id; 15 }h[N],th[N],Th[N]; 16 struct NODE{ 17 int p,id; 18 }L[N],R[N]; 19 bool cmp(node x,node y){ return x.x<y.x; } 20 bool cmp1(Node x,Node y){ 21 if (x.l!=y.l) return x.l<y.l; 22 else return x.r<y.r; 23 } 24 bool cmp2(Node x,Node y){ 25 if (x.r!=y.r) return x.r<y.r; 26 else return x.l<y.l; 27 } 28 void pre(int len){ 29 nums=numh=0; 30 for (int i=1;i<=cnt1;i++) 31 if (s[i].len>=2*len){ 32 ts[++nums].x=s[i].x; 33 ts[nums].len=s[i].len-2*len; 34 ts[nums].l=s[i].l+len; ts[nums].r=s[i].r-len; 35 } 36 for (int i=1;i<=cnt2;i++) 37 if (h[i].len>=2*len){ 38 th[++numh].y=h[i].y; 39 th[numh].len=h[i].len-2*len; 40 th[numh].l=h[i].l+len; th[numh].r=h[i].r-len; 41 th[numh].id=numh;//加入的id值 42 } 43 memcpy(Th,th,sizeof(th));//用临时数组把th存下来,因为之后th数组会被排序 44 } 45 bool check(int len){ 46 q.clear(); 47 q.insert(1e9);//防止lower_bound找到0 48 pre(len); 49 sort(ts+1,ts+1+nums,cmp); 50 sort(th+1,th+1+numh,cmp1); 51 for (int i=1;i<=numh;i++) 52 L[i].p=th[i].l,L[i].id=th[i].id;//按左端点排序 53 sort(th+1,th+1+numh,cmp2); 54 for (int i=1;i<=numh;i++) 55 R[i].p=th[i].r,R[i].id=th[i].id;//按右端点排序 56 L[numh+1].p=R[numh+1].p=ts[nums+1].x=1e9;//防止越界 57 int x=1,y=1,z=1; 58 while (x<=numh||y<=numh||z<=nums){ 59 int a=0,b=0,c=0; 60 if (L[x+a].p<=R[y].p&&L[x+a].p<=ts[z].x){ 61 q.insert(Th[L[x].id].y); 62 a++; 63 while (L[x+a-1].p==L[x+a].p) q.insert(Th[L[x+a].id].y),a++;//把相同左端点的都加到set中 64 } 65 if (ts[z+c].x<=L[x].p&&ts[z+c].x<=R[y].p){ 66 It s=q.lower_bound(ts[z].l); 67 if (*s<=ts[z].r) return true; 68 c++; 69 while (ts[z+c-1].x==ts[z+c].x){//查询,意义同上面 70 It s=q.lower_bound(ts[z+c].l); 71 if (*s<=ts[z+c].r) return true; 72 c++; 73 } 74 } 75 if (R[y].p<=L[x].p&&R[y].p<=ts[z].x){ 76 q.erase(Th[R[y].id].y); 77 b++; 78 while (R[y+b-1].p==R[y+b].p) q.erase(Th[R[y+b].id].y),b++;//删除,意义同上 79 } 80 x+=a; y+=b; z+=c;//不能直接把指针向后移 81 } 82 return false; 83 } 84 int main(){ 85 scanf("%d",&n); 86 for (int i=1;i<=n;i++){ 87 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 88 if (x1>x2) swap(x1,x2); 89 if (y1>y2) swap(y1,y2); 90 if (x1==x2){ 91 s[++cnt1].x=x1; s[cnt1].l=y1; s[cnt1].r=y2; s[cnt1].len=y2-y1; 92 } else{ 93 h[++cnt2].y=y1; h[cnt2].l=x1; h[cnt2].r=x2; h[cnt2].len=x2-x1; 94 } 95 } 96 l=1; r=1e9; ans=1e9; 97 while (l<=r){ 98 int mid=(l+r)>>1; 99 if (check(mid)){ 100 ans=mid; l=mid+1; 101 } else r=mid-1; 102 } 103 if (ans!=1e9) printf("%d\n",ans); 104 else puts("Human intelligence is really terrible"); 105 return 0; 106 }
以上是关于YYHS-Super Big Stupid Cross(二分+扫描线+平衡树)的主要内容,如果未能解决你的问题,请参考以下文章
HDU 4939 Stupid Tower Defense dp
使用Cro :: WebSocket :: Client添加授权或标头?
A1-2017级算法上机第一次练习赛 A The stupid owls
apache_conf 防止未经授权的目录浏览(来源:https://perishablepress.com/stupid-htaccess-tricks/#sec3)