bzoj 3165: [Heoi2013]Segment 动态凸壳
3165: [Heoi2013]Segment
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 202 Solved: 89
[Submit][Status]
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)%109+1)和((x
1+lastans-1)%39989+1,(y1+lastans-1)%109+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
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
0 3
HINT
对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。
据说这道题可以用线段树裸搞,但是我用的是线段树维护下凸壳,考试时候如果询问坐标x值有垂直线段的话,我直接输出的垂直线段,没有考虑线段高度问题,导致wa了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<cmath> using namespace std; #define PROB "segment" #define MAXN 60000 #define MAXT MAXN*17 #define VAL1 39989 #define VAL2 1000000000 #define lch (now<<1) #define rch (now<<1^1) #define INF 0x3f3f3f3f inline int nextInt() { register int x=0; register char ch; while (ch=getchar(),ch<'0' || ch>'9'); while (x=x*10+ch-'0',ch=getchar(),ch<='9' && ch>='0'); return x; } typedef double real; const int maxval=40000; struct point { real x,y; point(){} point(real x,real y):x(x),y(y){} point(int x,int y):x(x),y(y){} void print() { printf("(%.2lf,%.2lf) ",x,y); } }; struct line { point ps; real x,y; real angle; line(){} line(point p1,point p2) { ps=p1; x=p2.x-p1.x; y=p2.y-p1.y; angle=atan(y/x); } real cross_height(real xx) { // if (xx<ps.x || xx>ps.x+x)return -1e10; return ps.y + y*(xx-ps.x)/x; } point spos() { return ps; } point tpos() { return point(ps.x+x,ps.y+y); } void print() { printf("Line:"); spos().print(); tpos().print(); printf("\n"); } }ll[MAXN]; inline real xmul(line &l1,line l2) { return (l1.x*l2.y)-(l1.y*l2.x); } inline bool parallel(line &l1,line &l2) { return xmul(l1,l2)==0; } inline point crossover(line &l1,line &l2) { real s1=xmul(l1,line(l1.ps,l2.ps)); real s2=-xmul(l1,line(l1.ps,l2.tpos())); return point(l2.ps.x+l2.x*s1/(s1+s2), l2.ps.y+l2.y*s1/(s1+s2)); } int L[MAXT],R[MAXT],S[MAXT]; int V[MAXT]; real spos[MAXT],tpos[MAXT]; int topt; #define update(now) S[now]=S[L[now]]+S[R[now]]+1; #define l_rotate(now)\ t=R[now];\ R[now]=L[t];update(now);\ L[t]=now;update(t);\ now=t; #define r_rotate(now)\ t=L[now];\ L[now]=R[t];update(now);\ R[t]=now;update(t);\ now=t; inline void maintain(int &now) { register int t; if (S[L[L[now]]]>S[R[now]]) { r_rotate(now); maintain(L[now]); maintain(R[now]); maintain(now); return ; }else if (S[R[R[now]]]>S[L[now]]) { l_rotate(now); maintain(R[now]); maintain(L[now]); maintain(now); return ; }else if (S[R[L[now]]]>S[R[now]]) { l_rotate(L[now]); r_rotate(now); maintain(R[now]); maintain(L[now]); maintain(now); return ; }else if (S[L[R[now]]]>S[L[now]]) { r_rotate(R[now]); l_rotate(now); maintain(R[now]); maintain(L[now]); maintain(now); return ; } } int Insert(int &now,int id) { if (!now) { now=++topt; V[now]=id; S[now]=1; return now; } int ret; if (ll[id].angle<ll[V[now]].angle) ret=Insert(L[now],id); else ret=Insert(R[now],id); update(now); maintain(now); return ret; } void Delete(int &now,int aim) { if (now==aim) { if (!L[now] && !R[now]) { now=0; return ; } if (!L[now]) now=R[now]; else if (!R[now]) now=L[now]; else { register int t; r_rotate(now); Delete(R[now],aim); } update(now);maintain(now); return ; } if (ll[V[aim]].angle < ll[V[now]].angle || (ll[V[aim]].angle==ll[V[now]].angle && aim<now)) Delete(L[now],aim); else Delete(R[now],aim); update(now); maintain(now); } int Get_rank(int &now,int aim) { if (now==aim)return S[L[now]]+1; if (ll[V[aim]].angle < ll[V[now]].angle || (ll[V[aim]].angle==ll[V[now]].angle && aim<now)) return Get_rank(L[now],aim); else return S[L[now]]+1+Get_rank(R[now],aim); } int Get_kth(int &now,int rk) { if (rk==S[L[now]]+1)return now; if (rk<S[L[now]]+1) return Get_kth(L[now],rk); else return Get_kth(R[now],rk-S[L[now]]-1); } int spos_lower_bound(int &now,int ps) { if (!now)return -INF; if (spos[now]<ps) { int ret=spos_lower_bound(R[now],ps); if (ret!=-INF)return ret; else return now; }else { return spos_lower_bound(L[now],ps); } } void Scan(int now) { if (!now)return; Scan(L[now]); ll[V[now]].print(); printf(" At[%.2lf,%.2lf]\n",spos[now],tpos[now]); Scan(R[now]); } void Insert_line(int &root,int lid) { register int cur=Insert(root,lid); register int pa,pn; pa=pn=-1; register int rk; point pt; rk=Get_rank(root,cur); while (true) { if (rk==1)break; pa=Get_kth(root,rk-1); if (parallel(ll[V[pa]],ll[lid])) { if (ll[V[pa]].cross_height(1)>=ll[lid].cross_height(1)) { Delete(root,cur); return ; }else { Delete(root,pa); rk--; continue; } } pt=crossover(ll[V[pa]],ll[lid]); tpos[pa]=pt.x; if (tpos[pa]<=spos[pa]) { Delete(root,pa); rk--; } else break; } if (rk==1) spos[cur]=-1e10; else spos[cur]=pt.x; //rk=Get_rank(root,cur); while (true) { if (rk==S[root])break; pn=Get_kth(root,rk+1); if (parallel(ll[V[pn]],ll[lid])) { if (ll[V[pn]].cross_height(1)>=ll[lid].cross_height(1)) { Delete(root,cur); return ; }else { Delete(root,pn); continue; } } pt=crossover(ll[V[pn]],ll[lid]); spos[pn]=pt.x; if (tpos[pn]<=spos[pn]) Delete(root,pn); else break; } if (rk==S[root]) tpos[cur]=1e10; else tpos[cur]=pt.x; if (spos[cur]>=tpos[cur]) { Delete(root,cur); if (~pa && ~pn) spos[pn]=tpos[pa]=crossover(ll[V[pa]],ll[V[pn]]).x; else if (pa==-1) tpos[pn]=1e10; else spos[pa]=-1e10; } } pair<real,int> Search(int &root,int pos) { pair<real,int> res; int cur=spos_lower_bound(root,pos); if (cur==-INF)return make_pair(-1e100,0); res.second=V[cur]; res.first=ll[V[cur]].cross_height(pos); int rk=Get_rank(root,cur); if (rk==S[root])return res; int pa=Get_kth(root,rk+1); if (spos[pa]==pos) { res=min(res,make_pair(res.first,V[pa])); } return res; } struct sgt_node { int l,r; int root; }sgt[MAXT*4]; void Build_sgt(int now,int l,int r) { sgt[now].l=l;sgt[now].r=r; if (l+1==r)return ; int mid=(l+r)>>1; Build_sgt(lch,l,mid); Build_sgt(rch,mid,r); } void Add_sgt(int now,int l,int r,int x,int y,int lid) { if (l==x && r==y) { Insert_line(sgt[now].root,lid); return ; } int mid=(l+r)>>1; if (y<=mid) Add_sgt(lch,l,mid,x,y,lid); else if (mid<=x) Add_sgt(rch,mid,r,x,y,lid); else { Add_sgt(lch,l,mid,x,mid,lid); Add_sgt(rch,mid,r,mid,y,lid); } } pair<real,int> Query_sgt(int now,int l,int r,int pos) { pair<real,int> res=Search(sgt[now].root,pos); res.second=-res.second; if (l+1==r)return res; int mid=(l+r)>>1; if (pos<mid) return max(res,Query_sgt(lch,l,mid,pos)); else if (mid<pos) return max(res,Query_sgt(rch,mid,r,pos)); else return max(res,max(Query_sgt(lch,l,mid,pos),Query_sgt(rch,mid,r,pos))); } pair<int,int> ignall[MAXN]; int main() { freopen(PROB".in","r",stdin); //freopen(PROB".out","w",stdout); int n,m,x,y,z; int a,b,c,d; int opt; int lastans=0; m=nextInt(); // scanf("%d",&m); Build_sgt(1,1,maxval); n=1; for (int i=1;i<=m;i++) { opt=nextInt(); //scanf("%d",&opt); if (opt==0) { x=nextInt(); //scanf("%d\n",&x); x=((x+lastans-1)%VAL1+1); if (ignall[x]!=make_pair(0,0)) { //printf("%d\n",lastans=ignall[x].second); pair<real,int> res=Query_sgt(1,0,maxval,x); res.second=-res.second; if(ignall[x].first>res.first) printf("%d\n",lastans=ignall[x].second); else printf("%d\n",lastans=res.second); continue; } pair<real,int> res=Query_sgt(1,0,maxval,x); res.second=-res.second; printf("%d\n",lastans=res.second); }else { a=nextInt(),b=nextInt(),c=nextInt(),d=nextInt(); //scanf("%d%d%d%d",&a,&b,&c,&d); a=(a+lastans-1)%VAL1+1; c=(c+lastans-1)%VAL1+1; b=(b+lastans-1)%VAL2+1; d=(d+lastans-1)%VAL2+1; if (a>c)swap(a,c),swap(b,d); if (a==c) { if (ignall[a].first<max(b,d)) ignall[a]=make_pair(max(b,d),n); n++; continue; } ll[n++]=line(point(a,b),point(c,d)); Add_sgt(1,0,maxval,a,c,n-1); } } }
by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载
本博客已停用,新博客地址:http://mhy12345.xyz