您的位置:首页 > 其它

【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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: