【NOI2017模拟4.2】查询【线段树】
2017-04-06 20:58
381 查看
Description
给出若干条线段,用(x1,y1),(x2,y2)表示其两端点坐标,现在要求支持两种操作:0 x1 y1 x2 y2
表示加入一条新的线段,(x1,y1)-(x2,y2)
1 x0
询问所有线段中,x坐标在x0处的最高点的y坐标是什么,如果对应位置没有线段,则输出0。
Solution
这题一看就是用线段树做的。但是问题就是怎么维护。很明显我们要在区间维护一条直线。
但是如果有一条直线交了过去该怎么办?
假设我们现在要修改[l,r]这个区间,我们先在线段树上找到对应的子区间,然后这个子区间会有一条线段。
假设我们当前的线段可以完全高于这个区间上的线段,那么直接更新这个值。
否则:
我们设当前这条线段为a,区间维护的线段为b
如果mid在交点的左边:如果a在[l,mid]可以覆盖,那么把a和b交换(就是把当前线段改为b,维护线段改为a),然后向右继续搜。如果在[l,mid]没有覆盖,那么直接往右搜。
如果mid在交点的右边:如果a在[mid+1,r]可以覆盖,那么把a和b交换,然后向左继续搜。如果在[mid+1,r]没有覆盖,那么直接往左搜。
这样的时间复杂度是O(nlog2n)的
Code
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; const int maxn=2e5+7,mxx=1e6+maxn,inf=0x7fffffff; typedef double db; struct nod{ db p,q; }t[mxx*4]; int i,j,k,l,n,m,num,x,y,xx,yy,ha,da; bool bz[maxn]; db ans,kk,o,yi,er; void change(int x,int l,int r,int y,int z,db p,db q){ if(l==y&&r==z){ if(x==1572969){ o=o; } if(l==r||(db)(t[x].p-p)*(t[x].p+(r-l)*t[x].q-p-(r-l)*q)>0.0){ if(p>t[x].p)t[x].p=p,t[x].q=q; return; } int mid=(l+r)/2; yi=(db)t[x].p+(mid-l)*t[x].q; er=(db)p+(mid-l)*q; if((t[x].p-p)*(yi-er)>0){ if(er>yi){ swap(t[x].p,p),swap(t[x].q,q); change(x*2+1,mid+1,r,mid+1,z,p+q*(mid-y+1),q); } else{ change(x*2+1,mid+1,r,mid+1,z,p+q*(mid-y+1),q); } } else{ if(er>yi){ swap(t[x].p,p),swap(t[x].q,q); change(x*2,l,mid,y,mid,p,q); } else{ change(x*2,l,mid,y,mid,p,q); // change(x*2+1,mid+1,r,mid+1,z,p+q*(mid-y+1),q); } } return; } int mid=(l+r)/2; if(z<=mid)change(x*2,l,mid,y,z,p,q); else if(y>mid)change(x*2+1,mid+1,r,y,z,p,q); else{ change(x*2,l,mid,y,mid,p,q); change(x*2+1,mid+1,r,mid+1,z,p+q*(mid-y+1),q); } } void find(int x,int l,int r,int y){ ans=max(ans,t[x].p+(y-l)*t[x].q); if(l==r){ return; } int mid=(l+r)/2; if(y<=mid)find(x*2,l,mid,y); else find(x*2+1,mid+1,r,y); } int main(){ freopen("query.in","r",stdin); freopen("query.out","w",stdout); // freopen("fan.in","r",stdin); // freopen("fan.out","w",stdout); scanf("%d%d",&n,&m);da=1000001; fo(i,0,mxx*4-1)t[i].p=-9999999999; fo(i,1,n){ scanf("%d%d%d%d",&x,&y,&xx,&yy); if(x>xx)swap(x,xx),swap(y,yy); if(x==xx&&y>yy)swap(y,yy); x+=da,xx+=da;ha=x; if(xx==x)kk=inf;else kk=(db)(yy-y)/(xx-x); if(kk==inf)y=yy,kk=0; change(1,1,2*da,x,xx,y,kk); } fo(i,1,m){ scanf("%d",&k); if(k==0){ scanf("%d%d%d%d",&x,&y,&xx,&yy); if(x>xx)swap(x,xx),swap(y,yy); if(x==xx&&y>yy)swap(y,yy); if(x==180){ k=k; } x+=da,xx+=da;ha=x; if(xx==x)kk=inf;else kk=(db)(yy-y)/(xx-x); if(kk==inf)y=yy,kk=0; change(1,1,2*da,x,xx,y,kk); } else{ scanf("%d",&x); x+=da; ans=-9999999999; find(1,1,2*da,x); if(ans==-9999999999)ans=0; printf("%.6lf\n",ans); } } }
相关文章推荐
- 【JZOJ5039】【NOI2017模拟4.2】查询
- 【NOI2017模拟4.2】查询
- HDU 1556 Color the ball【线段树区间更新,一次查询+数组模拟】
- 【NOI2017模拟4.2】押韵
- 【JZOJ5040】【NOI2017模拟4.2】押韵
- poj--3067 Japan(线段树+单点更新区间查询)
- java模拟12306查询余票
- 分享自己做的一个简单的查询表达式模拟(ESQL,Linq)(2)
- .NET数据库的异步查询及模拟
- HDU 3308 线段树 最长连续上升子序列 单点更新 区间查询
- hdu5316 Magician (线段树+单点更新+区间查询+区间合并)
- HDU 2795 Billboard (线段树,单点查询)
- uva 1401 Fast Matrix Operations 快速矩阵操作 (线段树 区间修改和查询)
- hdu 4046 Panda (线段树 单点更新 区间查询)
- jzoj4417 【HNOI2016模拟4.1】神奇的字符串 (映射,权值线段树)
- HDOJ 5316 Magician【线段树 单点更新 区间查询】
- vijos 1659 河蟹王国 线段树区间加、区间查询最大值
- 喵哈哈村的魔法考试 Round #2 (Div.2) B.喵哈哈村的种花魔法 线段树 区间更新 单点查询
- 数据结构1 「在线段树中查询一个区间的复杂度为 $O(\log N)$」的证明
- http://acm.nbut.cn:8081/Problem/view.xhtml?id=1317&&线段树单点查询