2024.2.22模拟赛T3 题解

对于区间连边,可以线段树优化建图
对于单点连边,可以使用李超线段树维护迪杰斯特拉

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;
}

posted @ 2024-02-22 21:58  hubingshan  阅读(43)  评论(0)    收藏  举报