对于区间连边,可以线段树优化建图
对于单点连边,可以使用李超线段树维护迪杰斯特拉
code
#include<bits/stdc++.h>
using namespace std;
#define N 400005
#define int long long
#define pii pair<int,int>
#define fir first
#define sec second
int n,m,tot;
int val[N];
const int inf=1e18;
vector<pii > G[N];
void cun(int x,int y,int z){
G[x].push_back({y,z});
}
namespace JT{
int rt1,rt2;
int ls[N],rs[N];
int build(int l,int r,int op){
tot++;
if(l==r){
if(!op) cun(l,tot,0);
else cun(tot,l,0);
return tot;
}
int mid=(l+r)>>1,id=tot;
ls[id]=build(l,mid,op);
rs[id]=build(mid+1,r,op);
if(!op) cun(ls[id],id,0),cun(rs[id],id,0);
else cun(id,ls[id],0),cun(id,rs[id],0);
return id;
}
void lk(int p,int l,int r,int x,int y,int id,int w){
if(x<=l&&r<=y){
if(!w) cun(p,id,0);
else cun(id,p,w);
return ;
}
int mid=(l+r)>>1;
if(x<=mid) lk(ls[p],l,mid,x,y,id,w);
if(mid<y) lk(rs[p],mid+1,r,x,y,id,w);
}
}
namespace LCT{
int tot;
int c[N*4],ll[N*4],rr[N*4];
pii mn[N*4];
struct LINE{
int x,y,k,b;
}li[N];
int cal(int x,int p){
if(x<1||x>n) return inf;
return li[p].k*x+li[p].b;
}
void up(int p){
int ls=p*2,rs=p*2+1;
ll[p]=min(ll[ls],ll[rs]);
rr[p]=max(rr[ls],rr[rs]);
pii p1={cal(ll[p],c[p]),ll[p]},p2={cal(rr[p],c[p]),rr[p]};
mn[p]=min(p1,p2);
mn[p]=min(mn[p],mn[ls]);
mn[p]=min(mn[p],mn[rs]);
}
void build(int p,int l,int r){
if(l==r){
mn[p]={inf,0},ll[p]=rr[p]=l;
return ;
}
int mid=(l+r)>>1;
build(p*2,l,mid),build(p*2+1,mid+1,r);
up(p);
}
void pre(){li[0]={1,n,0,inf};build(1,1,n);}
void add(int p,int l,int r,int x){
if(l==r){
if(cal(l,x)<cal(l,c[p])) c[p]=x;
mn[p]={cal(ll[p],c[p]),ll[p]};
return ;
}
int mid=(l+r)>>1;
if(cal(mid,x)<cal(mid,c[p])) swap(x,c[p]);
if(cal(l,x)<cal(l,c[p])) add(p*2,l,mid,x);
if(cal(r,x)<cal(r,c[p])) add(p*2+1,mid+1,r,x);
up(p);
}
void ding(int p,int l,int r,int x,int y,int u){
if(x<=l&&r<=y){
add(p,l,r,u);
return ;
}
int mid=(l+r)>>1;
if(x<=mid) ding(p*2,l,mid,x,y,u);
if(mid<y) ding(p*2+1,mid+1,r,x,y,u);
up(p);
}
void dell(int p,int l,int r,int x){
if(l==r){
mn[p]={inf,0};
assert(rr[p]);
ll[p]=n+1,rr[p]=0;
return ;
}
int mid=(l+r)>>1;
if(x<=mid) dell(p*2,l,mid,x);
else dell(p*2+1,mid+1,r,x);
up(p);
}
void ins(int x,int y,int k,int b){
if(x>y) return ;
li[++tot]={x,y,k,b};
ding(1,1,n,x,y,tot);
}
}
int dis[N],u[N];
priority_queue<pii,vector<pii >,greater<pii > > q;
void add(int x){
LCT::ins(1,x-1,-val[x],dis[x]+val[x]*x);
LCT::ins(x+1,n,val[x],dis[x]-val[x]*x);
}
void del(int x){
u[x]=1;
if(x<=n) LCT::dell(1,1,n,x);
}
pii gt_qm(){
if(q.empty()) return {inf,0};
pii p=q.top();
while(u[p.sec]){
q.pop();
if(q.empty()) return {inf,0};
p=q.top();
}
return p;
}
void dij(){
memset(dis,9,sizeof(dis));
LCT::pre();
dis[1]=0,q.push({0,1});
for(int zu=1,x;zu<=tot;zu++){
pii p1=gt_qm();
pii p2=LCT::mn[1];
if(p1<=p2) x=p1.sec,dis[x]=min(dis[x],p1.fir),q.pop();
else x=p2.sec,dis[x]=min(dis[x],p2.fir);
//printf("dij: x=%lld p1=(%lld,%lld) p2=(%lld,%lld)\n",x,p1.fir,p1.sec,p2.fir,p2.sec);
if(!x) break;
del(x);
for(auto p:G[x]){
int y=p.fir,z=p.sec;
// printf("zhuan: %lld %lld\n",y,z);
if(dis[y]>dis[x]+z) dis[y]=dis[x]+z,q.push({dis[y],y});
}
if(val[x]) add(x);
}
}
signed main(){
freopen("tunnel.in","r",stdin);
freopen("tunnel.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&val[i]);
tot=n,JT::rt1=JT::build(1,n,0),JT::rt2=JT::build(1,n,1);
for(int i=1,sl,sr,tl,tr,w;i<=m;i++){
scanf("%lld%lld%lld%lld%lld",&sl,&sr,&tl,&tr,&w);tot++;
JT::lk(JT::rt1,1,n,sl,sr,tot,0),JT::lk(JT::rt2,1,n,tl,tr,tot,w);
}
dij();
if(dis[n]<dis[0]) printf("%lld\n",dis[n]);
else printf("-1\n");
return 0;
}
标签:2024.2,22,rs,int,题解,void,tot,ls,id
From: https://www.cnblogs.com/hubingshan/p/18028324