专栏文章

【1】做题心得 - 2025 NOIP #65 - T2【凸包】

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min4wxdh
此快照首次捕获于
2025/12/01 20:37
3 个月前
此快照最后确认于
2025/12/01 20:37
3 个月前
查看原文
显然边只选一条,所以会有最短路为:
dis(1,u)+w(u,v)+dis(v,n)dis(1,u)+w(u,v)+dis(v,n)
求这个的最小值,由于 w(u,v)=wiktiw(u,v)=w_i-kt_i,一次函数,以 wiw_i 为横坐标即可。所以这是一个凸包。考虑一个维护凸包的东西做即可。但是我不会 Slope。
CPP
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e5+10;
vector<array<ll,3>>e[N],g[N];
int n,m,Q,stk[N],top;
ll dep[N],dep2[N],k,ans,x[N],y[N],tot;
bool vis[N];
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > >q;
void dij(ll dep[],vector<array<ll,3>>E[],int ty){
	for(int i=1;i<=n;i++)
		dep[i]=1e18, vis[i]=0;
	q.push({0,(ty?n:1)});
	dep[(ty?n:1)]=0;
	while(q.size()){
		auto f=q.top();
		ll p=f.second,d=f.first;
		q.pop();
		if(vis[p]) continue;
		vis[p]=1;
		for(auto ED:E[p]){
			int v=ED[0];
			ll w=ED[1];
			if(d+w<dep[v]){
				dep[v]=d+w;
				if(!vis[v]) q.push({dep[v],v});
			}
		}
	}
	return;
}
void solve(){
	for(int i=1;i<=n;i++)
		e[i].clear(),
		g[i].clear();
	cin>>n>>m;
	bool wt=1;
	tot=0;
	for(int i=1;i<=m;i++){
		ll u,v,w,t;
		cin>>u>>v>>t>>w;
		e[u].push_back({v,t,w});   
		g[v].push_back({u,t,w}); 
		x[++tot]=w, y[tot]=1e18;
		wt&=(w==1);
	}
	sort(x+1,x+tot+1);
	tot=unique(x+1,x+tot+1)-x-1;
	dij(dep,e,0);
	dij(dep2,g,1);
	for(int u=1;u<=n;u++)for(auto ED:e[u]){
		int v=ED[0]; ll t=ED[1], w=ED[2];
		w=lower_bound(x+1,x+tot+1,w)-x;
		y[w]=min(y[w],dep[u]+t+dep2[v]);
	}
	top=0;
	for(int i=1;i<=tot;i++){
		while(top>=2){
			ll ya=y[stk[top]],yb=y[stk[top-1]],
			   xa=x[stk[top]],xb=x[stk[top-1]];	
			if((ya-yb)*(__int128)(x[i]-xa)>(xa-xb)*(__int128)(y[i]-ya))
				--top;
			else break;
		}
		stk[++top]=i;
	}
	cin>>Q;
	while(Q--){         
		cin>>k;
		if(wt)cout<<dep[n]-k<<"\n";
		else{
			int l=0,r=top;
			while(l+1<r){
				int mid=(l+r)/2;
				if(y[stk[mid+1]]-y[stk[mid]]>k*(x[stk[mid+1]]-x[stk[mid]]))
					r=mid;
				else 
					l=mid;
			}
			cout<<y[stk[r]]-k*x[stk[r]]<<"\n";
		}
	}
	return ;
}
int main(){
	freopen("kiongozi.in","r",stdin);
	freopen("kiongozi.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T;
	cin>>T;
	while(T--) solve();
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...