想知道剛入職的00後參加網路資訊保安技能競賽,是如何獲獎的麼?
阿新 • • 發佈:2021-10-21
李超線段樹可以用來維護平面上的線段(但是要求 \(x\) 或 \(y\) 其中一維比較小,在 \(10^5\) 及以內)。
稱一條線段能成為區間 \([l,r]\) 中的最優線段,當且僅當:
-
該線段的定義域完整覆蓋了區間 \([l,r]\) ;
-
該線段在區間中點處最優。
題意:給定平面上的一些線段,每次詢問求出當前與 \(x=k\) 相交的線段中 \(y\) 值最大的線段編號。
直接按照題目題意來建立線段樹並查詢即可。
#define eps 1e-8 #define Maxn 100005 #define MAX 66005 #define mod 39989 #define pa pair<double,double> #define fi first #define se second typedef long long ll; int n,tot; int tree[Maxn<<2]; pa Line[Maxn]; inline double f(pa y,int x) { return y.fi*x+y.se; } inline int tomax(int a,int b,int x) { return (f(Line[a],x)>f(Line[b],x)+eps)?a:b; } void add(int p,int nl,int nr,int k,int l,int r) { int mid=(nl+nr)>>1; if(nl>=l && nr<=r) { if(f(Line[k],mid)>f(Line[tree[p]],mid)+eps) swap(tree[p],k); if(f(Line[k],nl)>f(Line[tree[p]],nl)+eps) add(p<<1,nl,mid,k,l,r); if(f(Line[k],nr)>f(Line[tree[p]],nr)+eps) add(p<<1|1,mid+1,nr,k,l,r); return; } if(mid>=l) add(p<<1,nl,mid,k,l,r); if(mid<r) add(p<<1|1,mid+1,nr,k,l,r); } int query(int p,int nl,int nr,int x) { if(nl==nr) return tree[p]; int mid=(nl+nr)>>1; if(mid>=x) return tomax(tree[p],query(p<<1,nl,mid,x),x); else return tomax(tree[p],query(p<<1|1,mid+1,nr,x),x); return 0; } int main() { n=rd(); for(int i=1,opt,a1,b1,a2,b2,k,Last=0;i<=n;i++) { opt=rd(); if(opt==1) { a1=(rd()+Last-1)%mod+1,b1=(rd()+Last-1)%1000000000+1; a2=(rd()+Last-1)%mod+1,b2=(rd()+Last-1)%1000000000+1; if(a1==a2) Line[++tot]=pa(0.0,1.0*max(b1,b2)); else Line[++tot]=pa(1.0*(b2-b1)/(a2-a1),1.0*b1-1.0*(b2-b1)/(a2-a1)*a1); add(1,1,MAX,tot,min(a1,a2),max(a1,a2)); } else k=(rd()+Last-1)%mod+1,printf("%d\n",Last=query(1,1,MAX,k)); } return 0; }