您的位置:首页 > 其它

bzoj3165 [Heoi2013]Segment

2017-08-22 20:10 330 查看
Description

要求在平面直角坐标系下维护两个操作:

1.在平面上加入一条线段。记第i条被插入的线段的标号为i。

2.给定一个数k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。

Input

第一行一个整数n,表示共n 个操作。

接下来n行,每行第一个数为0或1。

若该数为 0,则后面跟着一个正整数 k,表示询问与直线

x = ((k +lastans–1)%39989+1)相交的线段中交点(包括在端点相交的情形)最靠上的线段的编号,其中%表示取余。若某条线段为直线的一部分,则视作直线与线段交于该线段y坐标最大处。若有多条线段符合要求,输出编号最小的线段的编号。

若该数为 1,则后面跟着四个正整数 x0, y0, x 1, y 1,表示插入一条两个端点为

((x0+lastans-1)%39989+1,(y0+lastans-1)%10^9+1)和((x

1+lastans-1)%39989+1,(y1+lastans-1)%10^9+1) 的线段。

其中lastans为上一次询问的答案。初始时lastans=0。

Output

对于每个 0操作,输出一行,包含一个正整数,表示交点最靠上的线段的编号。若不存在与直线相交的线段,答案为0。

Sample Input

6

1 8 5 10 8

1 6 7 2 6

0 2

0 9

1 4 7 6 7

0 5

Sample Output

2

0 3

HINT

对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。

分析:

终于要学习新的数据结构了

灰常的兴奋啊~~

新知识的学习从抄板子开始

从零开始的数据结构学习。。。

丁队的板子。。。看不懂

只能上网找资源orz

李超线段树板子





这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>

using namespace std;

const double eps=1e-10;
const int swt=1000000000;
const int N=100010;
const int mod=39989;
struct nd{
int x,y,ff;
};
nd tree[N<<2];
struct node{
int x,y;
double k,b;
double f(int x){
return k*x+b;
}
};
node li
;  //线段
int lastans,tot=0,ansi,wi
;
double ansy,wy
;  //ansy记录最大坐标,ansi记录线段编号

int dcmp(double x)
{
if (fabs(x)<eps) return 0;
else if (x>0) return 1;
else return -1;
}

int cross(int u,int w)  //交点
{
return floor((li[w].b-li[u].b)/(li[u].k-li[w].k));
}

node getline(int x,int y,int xx,int yy)
{
node ans;
ans.x=min(x,xx);  //定义域
ans.y=max(x,xx);
if (ans.x!=ans.y){
ans.k=(double)(yy-y)/(double)(xx-x);
ans.b=y-x*ans.k;  //kx+b=y
}
else ans.k=0.0,ans.b=max(y,yy);  //一条竖线
return ans;
}

void update(int u,int x)  //x=u和线段的交点
{
double y=li[x].f(u);
int p=dcmp(y-wy[u]);
if (!wi[u]||(p>0||(p==0&&x<wi[u])))
{
wy[u]=y;   //维护端点值
wi[u]=x;
}
}

void build(int bh,int l,int r)
{
tree[bh].x=l;
tree[bh].y=r;
tree[bh].ff=0;
if (l==r) return;
int mid=(l+r)>>1;
build(bh<<1,l,mid); build(bh<<1|1,mid+1,r);
}

void insert(int bh,int u)  //把每个线段分成logn个区间
{
if (li[u].x<=tree[bh].x&&li[u].y>=tree[bh].y)  //线段树节点完全包含线段
{
if (!tree[bh].ff){
tree[bh].ff=u;return;  ///没被覆盖过
}
int mid=(tree[bh].x+tree[bh].y)>>1;
int ll=dcmp(li[u].f(tree[bh].x)-li[tree[bh].ff].f(tree[bh].x));
int rr=dcmp(li[u].f(tree[bh].y)-li[tree[bh].ff].f(tree[bh].y));
//通过f函数计算线段树节点的左右端点与两条线段的交点
if (ll>0&&rr>0)  //完全覆盖
tree[bh].ff=u;
else if (ll>0||rr>0) //李超线段树的精髓啊
{
int tt=cross(tree[bh].ff,u);
if (tt<=mid&&ll>0) insert(bh<<1,u);
if (tt<=mid&&rr>0) insert(bh<<1,u),tree[bh<<1|1].ff=u;  //
if (tt>mid&&rr>0) insert(bh<<1|1,u);
if (tt>mid&&ll>0) insert(bh<<1|1,u),tree[bh<<1].ff=u;  //
} else update(tree[bh].x,u),update(tree[bh].y,u);
return;
}
int mid=(tree[bh].x+tree[bh].y)>>1;
if (li[u].x<=mid) insert(bh<<1,u);
if (li[u].y>mid) insert(bh<<1|1,u);
}

void ask(int bh,int u)
{
if (tree[bh].ff)
{
double y=li[tree[bh].ff].f(u);
int s=dcmp(y-ansy);
if (s>0||(s==0&&ansi>tree[bh].ff))
ansy=y,ansi=tree[bh].ff;
}
if (tree[bh].x==tree[bh].y) return;
int mid=(tree[bh].x+tree[bh].y)>>1;
if (u<=mid) ask(bh<<1,u);
if (u>mid) ask(bh<<1|1,u);
}

int main()
{
int T;
scanf("%d",&T);
build(1,1,mod);
while (T--)
{
int opt,x,y,xx,yy;
scanf("%d",&opt);
if (opt==1)
{
scanf("%d%d%d%d",&x,&y,&xx,&yy);
x=(x+lastans-1)%mod+1;y=(y+lastans-1)%swt+1;
xx=(xx+lastans-1)%mod+1;yy=(yy+lastans-1)%swt+1;
li[++tot]=getline(x,y,xx,yy);
insert(1,tot);
}
else
{
scanf("%d",&x);
x=(x+lastans-1)%mod+1;
ansi=0;ansy=-1.0;
ask(1,x);
int s=dcmp(wy[x]-ansy);
if (s>0||(s==0&&wi[x]<ansi)) ansi=wi[x];
lastans=ansi;
printf("%d\n",lastans);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: