李超线段树
根据函数的单调性与函数间的交点,维护/求若干条线段/直线在某个位置的最值,可用于优化斜率优化dp
模板题 求若干条线段在某个横坐标上的最大值,区间修改单点查询动态开点版
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10,rm=39989;
typedef double db;
typedef pair<double,int> pdi;
const db eps=1e-9;
int n,opt,lans,cnt;
struct node{
db k,b;
int x0,y0,x1,y1;
inline db calc(db x){
return k*x+b;
}
}p[maxn];
int t[maxn<<4],lc[maxn<<4],rc[maxn<<4],tot,root;
bool cmp(int i,int j,int x){
double ansi=p[i].calc(x),ansj=p[j].calc(x);
if(ansi-ansj>eps) return 1;
if(ansj-ansi>eps) return 0;
return i<j;
}
inline void upd(int &u,int l,int r,int k){
if(!u) u=++tot;
int mid=(l+r)>>1;
if(!t[u]){
t[u]=k;
return;
}
if(cmp(k,t[u],mid)) swap(k,t[u]);
if(l==r) return;
if(cmp(k,t[u],l)) upd(lc[u],l,mid,k);
if(cmp(k,t[u],r)) upd(rc[u],mid+1,r,k);
}
inline void update(int &u,int ql,int qr,int l,int r,int k){
if(!u) u=++tot;
if(ql==l&&qr==r){
upd(u,ql,qr,k);
return;
}
int mid=(l+r)>>1;
if(ql<=mid) update(lc[u],ql,min(qr,mid),l,mid,k);
if(qr>mid) update(rc[u],max(ql,mid+1),qr,mid+1,r,k);
}
inline int qry(int u,int l,int r,int k){
if(!u) return 0;
if(l==r) return t[u];
int mid=(l+r)>>1,ans=t[u],son;
if(k<=mid){
son=qry(lc[u],l,mid,k);
if(cmp(son,ans,k)) ans=son;
}
else{
son=qry(rc[u],mid+1,r,k);
if(cmp(son,ans,k)) ans=son;
}
return ans;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
p[0].k=0,p[0].b=-2e9;
for(int i=1;i<=n;i++){
cin>>opt;
if(opt){
++cnt;
cin>>p[cnt].x0>>p[cnt].y0>>p[cnt].x1>>p[cnt].y1;
p[cnt].x0=(p[cnt].x0+lans-1)%39989+1,p[cnt].y0=(p[cnt].y0+lans-1)%1000000000+1;
p[cnt].x1=(p[cnt].x1+lans-1)%39989+1,p[cnt].y1=(p[cnt].y1+lans-1)%1000000000+1;
if(p[cnt].x0>p[cnt].x1) swap(p[cnt].x0,p[cnt].x1),swap(p[cnt].y0,p[cnt].y1);
if(p[cnt].x1==p[cnt].x0){
p[cnt].k=0,p[cnt].b=max(p[cnt].y0,p[cnt].y1);
update(root,p[cnt].x1,p[cnt].x1,1,rm,cnt);
}
else{
p[cnt].k=1.0*(p[cnt].y0-p[cnt].y1)/(p[cnt].x0-p[cnt].x1);
p[cnt].b=p[cnt].y0-p[cnt].x0*p[cnt].k;
update(root,p[cnt].x0,p[cnt].x1,1,rm,cnt);
}
}
else{
int x;
cin>>x;
x=(x+lans-1)%39989+1;
lans=qry(root,1,rm,x);
cout<<lans<<'\n';
}
}
return 0;
}
CF932F Escape Through Leaf 动态开点+线段树合并
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int lm=-1e5,rm=1e5,maxn=1e5+10;
typedef long long ll;
const ll inf=1e18;
int n,va[maxn],vb[maxn];
int tot,to[maxn<<1],nxt[maxn<<1],h[maxn];
inline void adde(int x,int y){
to[++tot]=y;
nxt[tot]=h[x];
h[x]=tot;
}
int sum,t[maxn<<5],lc[maxn<<5],rc[maxn<<5],root[maxn<<5],cnt;
ll k[maxn],b[maxn];
inline ll calc(int i,ll x){
return k[i]*x+b[i];
}
inline bool cmp(int i,int j,int x){
ll y1=calc(i,x),y2=calc(j,x);
return y1<y2;
}
inline void upd(int &u,int l,int r,int k){
if(!u) u=++sum;
if(!t[u]){
t[u]=k;
return;
}
if(l==r){
if(cmp(k,t[u],l)) t[u]=k;
return;
}
int mid=(l+r)>>1;
if(cmp(k,t[u],mid)) swap(k,t[u]);
if(cmp(k,t[u],l)) upd(lc[u],l,mid,k);
if(cmp(k,t[u],r)) upd(rc[u],mid+1,r,k);
}
inline ll qry(int u,int l,int r,int k){
if(!u) return inf;
if(l==r) return calc(t[u],k);
int mid=(l+r)>>1;
ll ans=calc(t[u],k);
if(k<=mid) ans=min(ans,qry(lc[u],l,mid,k));
else ans=min(ans,qry(rc[u],mid+1,r,k));
return ans;
}
inline int combine(int ua,int ub,int l,int r){
if(!ua||!ub) return ua+ub;
if(l==r){
if(cmp(t[ub],t[ua],l)) return ub;
return ua;
}
int mid=(l+r)>>1;
lc[ua]=combine(lc[ua],lc[ub],l,mid);
rc[ua]=combine(rc[ua],rc[ub],mid+1,r);
upd(ua,l,r,t[ub]);
return ua;
}
ll ans[maxn];
inline void dd(int x,int f){
bool du=0;
for(int i=h[x];i;i=nxt[i]){
int y=to[i];
if(y==f) continue;
du=1;
dd(y,x);
root[x]=combine(root[x],root[y],lm,rm);
}
if(du) ans[x]=qry(root[x],lm,rm,va[x]);
k[++cnt]=vb[x];
b[cnt]=ans[x];
upd(root[x],lm,rm,cnt);
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
k[0]=0;
b[0]=inf;
cin>>n;
for(int i=1;i<=n;i++) cin>>va[i];
for(int i=1;i<=n;i++) cin>>vb[i];
for(int i=1,u,v;i<n;i++) cin>>u>>v,adde(u,v),adde(v,u);
dd(1,0);
for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
return 0;
}

浙公网安备 33010602011771号