至今不會李超線段樹\(.jpg\)……
先說明一下,李超線段樹只能解決「只插入」的問題,如果有刪除恕它無能為力
先考慮這麼乙個問題,我們要資瓷動態插入直線以及詢問直線\(x=k\)與其它所有直線相交的點中最大的\(y\)座標是多少
李超線段樹的具體過程是這樣的
對於乙個區間,我們維護該區間的所有直線中,從上往下去看可以看到它的長度最大的一條直線(即沒有被其他直線覆蓋的長度最大) (litble語)
我們插入一條直線的時候就需要分類討論了,以下稱插入直線為當前直線,之前的直線為記錄直線
1.如果沒有記錄直線,把記錄直線變成當前直線,返回
2.當前直線在這個區間中被記錄直線完全覆蓋,直接返回
3.當前直線在這個區間中完全覆蓋記錄直線,把記錄直線變成當前直線,返回
4.如果上面情況都不滿足,那麼這個區間中兩條直線顯然有交點,我們求出交點的\(x\)座標,根據\(x\)與區間中點的大小關係判斷哪條直線未被覆蓋的長一點,把記錄直線變成長一點的那個,另一條直線繼續遞迴
因為第四步中我們區間長度至少減少一半,所以它的複雜度是\(o(n\log n)\)的
這就是我們之前說的操作啦,直接上李超線段樹就行了
//minamoto
#include#define r register
#define fp(i,a,b) for(r int i=(a),i=(b)+1;ii;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
templateinline bool cmax(t&a,const t&b)
double readdb()
inline char getop()
char sr[1<<21],z[20];int c=-1,z=0;
inline void ot()
void print(r int x)
const int n=1e5+5;
struct node
inline double val(const r int &x)
}pool[n<<2],*rt;int tot;
inline node *newnode()
int n,x,q;double b,k,bb,kk,res;char op;
void build(node* &p,int l,int r)
void query(node *p,int l,int r)
void update(node *p,int l,int r)else
}int main()
return ot(),0;
}
//minamoto
#include#define r register
#define fp(i,a,b) for(r int i=(a),i=(b)+1;ii;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
templateinline bool cmax(t&a,const t&b)
char sr[1<<21],z[20];int c=-1,z=0;
inline void ot()
void print(r int x)
const int m=39989,l=1e9,n=1e5+5;
struct node
inline double calc(const r int &x)
}pool[n<<2],*rt;int tot;
int n,q,id,ii,ql,qr,res,x;double b,k,bb,kk,mx;
inline node *newnode()
void build(node* &p,int l,int r)
void update(node *p,int l,int r,double b,double k,int id)else
return;
}int mid=(l+r)>>1;
if(ql<=mid)update(p->lc,l,mid,b,k,id);
if(qr>mid)update(p->rc,mid+1,r,b,k,id);
}void query(node *p,int l,int r)
int cnt,op,val[n],id[n];
int main()
if(x0>x1)swap(x0,x1),swap(y0,y1);
k=1.0*(y1-y0)/(x1-x0),b=y0-k*x0,id=cnt,ql=x0,qr=x1;
update(rt,1,n,b,k,id);
}else
}return ot(),0;
}
如果我們把路徑拆成兩段,那麼這個路徑加可以看成是乙個一次函式
具體來說,設\(dis_u\)表示節點\(u\)到根節點的距離,那麼\((x,lca)\)這條路徑上每個節點的權值就會加上\(-dis_ua+dis_xa+b\),而\((lca,y)\)這條路徑上每個節點就會加上\(dis_ua+a(dis_x+2\times dis_)+b\)
區間加一次函式並維護最值,就是李超線段樹啦~~~~
我們把它給樹剖了,那麼同一條重鏈裡\(dis\)肯定是遞增的,我們就可以把插入直線變成插入線段
順便注意我們的線段樹上的節點是離散化之後的,所以在李超線段樹計算的時候要用原來的\(dis\)進行計算
樹剖乙個\(\log\),李超線段樹兩個\(\log\),總複雜度是\(o(n\log^3n)\)
//minamoto#include#define r register
#define ll long long
#define inf 123456789123456789ll
#define fp(i,a,b) for(r int i=(a),i=(b)+1;ii;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
templateinline bool cmin(t&a,const t&b)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc()
int read()
char sr[1<<21],z[20];int c=-1,z=0;
inline void ot()
void print(r ll x)
const int n=1e5+5;
struct ege[n<<1];int head[n],tot;
inline void add(r int u,r int v,r int w),head[u]=tot;}
ll dis[n],bb,kk;int dfn[n],rk[n],top[n],fa[n],sz[n],son[n],dep[n];
int n,m,cnt;
void dfs1(int u)
}void dfs2(int u,int t)
int lca(r int u,r int v)
inline ll calc(r ll x)
}pool[n<<2],*rt;int num;
inline node *newnode()
int ql,qr;ll res,k,b;
void build(node* &p,int l,int r)
void update(node *p,int l,int r,ll b,ll k)else
p->upd();
return;
}int mid=(l+r)>>1;
if(ql<=mid)update(p->lc,l,mid,b,k);
if(qr>mid)update(p->rc,mid+1,r,b,k);
p->upd();
}void query(node *p,int l,int r)
void change(int u,int v)
ql=dfn[v],qr=dfn[u],update(rt,1,n,b,k);
}void ask(int u,int v){
res=inf;
while(top[u]!=top[v]){
if(dep[top[u]]
李超線段樹學習筆記
至今不會李超線段樹 jpg 先說明一下,李超線段樹只能解決 只插入 的問題,如果有刪除恕它無能為力 先考慮這麼乙個問題,我們要資瓷動態插入直線以及詢問直線 x k 與其它所有直線相交的點中最大的 y 座標是多少 李超線段樹的具體過程是這樣的 對於乙個區間,我們維護該區間的所有直線中,從上往下去看可以...
李超線段樹學習筆記
李超線段樹支援這樣的操作 插入一條直線。詢問與 x x 0 相交的點的最大 小的縱座標 接下來我們以最大值為例 它基於線段樹的標記永久化,也就是說,我們對於區間 l,r 維護 x mid 上最高的直線的編號 但是如果 l,r 的所有點都以 l,r 的父親記錄的直線作為最大值,那麼 l,r 的子樹都沒...
李超線段樹
首先來看一道題 heoi2013 segment 可以發現的是,實質上某個 x k 處的最大值只有乙個,因此我們需要盡可能減少計算不優的線段。那麼對於兩條線段 a,b a ne b 它們左右端點橫座標相同,就只會產生如下四種情況 從特殊情況出發,每次我們都插入一條 1,n 的線段。如果是前兩條情況,...