1. 程式人生 > 程式設計 >帶你精通Python正則表示式

帶你精通Python正則表示式

李超線段樹

用途:給定 $\mathrm{n}$ 個 $\mathrm{y}=\mathrm{kx}+\mathrm{b}$ 形式的線段,問 $\mathrm{x}=\mathrm{x[0]}$ 與哪條線段交點的縱座標值最大.

對於李超樹的每一個區間,維護這條區間的 “優勢線段”,即區間 $\mathrm{mid}$ 位置上縱座標最大的線段.

當在區間中插入一條線段時,按照下列步驟:

1. 若新插入線段中點位置大於當前線段,則該區間的優勢線段更新為新線段,並將當前線段向下遞迴更新.

2. 若將遞迴更新的線段左/右端點的值小於優勢線段,顯然會完全被覆蓋掉,就沒有必要繼續遞迴了.

3. 若滿足遞迴條件,則遞迴繼續更新.

插入線段時間複雜度為 $O(n \log ^2 n)$,查詢複雜度為 $O(n \log n)$.

Segment

來源:洛谷P4097 [HEOI2013]Segment

模板題,注意線段的 $\mathrm{x[0]}=\mathrm{x[1]}$ 時將斜率取為 $0$ 即可.

#include <cstdio>
#include <cstring> 
#include <cmath>
#include <vector> 
#include <set>
#include <algorithm>
#define M  50003
#define N  100009 
#define ll long long 
#define pb push_back 
#define ls (now<<1) 
#define rs (now<<1|1)    
#define setIO(s) freopen(s".in","r",stdin)    
using namespace std; 
const int mod=39989; 
const double eps=1e-8;
int tree[N<<2];   
struct seg {
    double k,b;   
    seg(double i=0.0,double j=0.0) { k=i,b=j;}    
}s[N];  
double calc(seg o, int x) {
    return o.k*x+o.b;  
}    
void modify(int l,int r,int now,int L,int R,int x) {
    int mid=(l+r)>>1;  
    if(l>=L&&r<=R) {
        if(calc(s[x],mid)-calc(s[tree[now]],mid)>eps) swap(x, tree[now]);    
        if(calc(s[x],l)-calc(s[tree[now]],l)>eps) 
            modify(l,mid,ls,L,R,x); 
        if(calc(s[x],r)-calc(s[tree[now]],r)>eps) 
            modify(mid+1,r,rs,L,R,x);  
        return ; 
    }
    if(L<=mid) modify(l,mid,ls,L,R,x); 
    if(R>mid)  modify(mid+1,r,rs,L,R,x);  
}    
void upd(int &x,int o,int p) {
    double yx=s[x].k*p+s[x].b;  
    double yo=s[o].k*p+s[o].b;   
    if(yo-yx>=eps||(abs(yo-yx)<=eps&&o<x)) x=o;    
}
int query(int l,int r,int now,int p) {
    if(l==r) {
        return tree[now]; 
    }
    int mid=(l+r)>>1,id=tree[now];     
    if(p<=mid)  upd(id, query(l,mid,ls,p), p);  
    else upd(id, query(mid+1,r,rs,p), p);  
    return id;         
}
int main() { 
    // setIO("input");      
    // freopen("input.out","w",stdout);   
    int Q,lastans=0,n=0;  
    scanf("%d",&Q); 
    while(Q--) {
        int op; 
        scanf("%d",&op);  
        if(op==0) {
            int k,x; 
            scanf("%d",&k);  
            k=(k+lastans-1)%mod+1;  
            printf("%d\n",lastans=query(1,M,1,k));    
        }
        else {
            int x[2],y[2];  
            scanf("%d%d%d%d",&x[0],&y[0],&x[1],&y[1]);  
            x[0]=(x[0]+lastans-1)%mod+1;  
            y[0]=(y[0]+lastans-1)%1000000000+1;    
            x[1]=(x[1]+lastans-1)%mod+1; 
            y[1]=(y[1]+lastans-1)%1000000000+1;                            
            if(x[0]==x[1]) {
                s[++n].k=0,s[n].b=max(y[0], y[1]);    
            }
            else {
                s[++n].k=(double)1.0*(y[1]-y[0])/(x[1]-x[0]);  
                s[n].b=y[0]-1.0*s[n].k*x[0];     
            }
            if(x[0]>x[1]) swap(x[0],x[1]); 
            modify(1,M,1,x[0],x[1],n);  
        }
    }
    return 0; 
}