LOJ#3156. 「NOI2019」回家路线(前缀和优化建图+for循环+凸包)

传送门
来一发大常数做法(然而网络赛的时候凸包插点的方向写反了。。。 40 p t s 40pts 40pts滚了什么我居然还有40
对于一条边 ( u , v , p , q ) (u,v,p,q) (u,v,p,q),我们把二元组 ( v , q ) (v,q) (v,q)看成一个点。
这样下来一共有 m m m个点。
假设每个点对应有 l e n 1 i len1_i len1i个二元组 ( i , v a l 1 i , j ) (i,val1_{i,j}) (i,val1i,j),每个时间点对应有 l e n 2 i len2_i len2i个二元组 ( v a l 2 i , j , i ) (val2_{i,j},i) (val2i,j,i)
然后重新处理每条边。
对于边 ( u , v , p , q ) (u,v,p,q) (u,v,p,q),我们在 u u u对应的时间点中二分出离 q q q最近的 v a l 1 u , t val1_{u,t} val1u,t,建边 ( u , v a l 1 u , t ) → ( v , q ) (u,val1_{u,t})\rightarrow(v,q) (u,val1u,t)(v,q),如果所有的时间点都比 q q q大就不用建了。
然后我们就建出来了一个 D A G DAG DAG,且如果我们按照时间点为关键字来 f o r for for循环更新最短路的话好像就完了???
恭喜你有 40 p t s 40pts 40pts 因为有40 p t s pts pts的点是不需要建凸包转移其它边的
那么其它边指的是什么边呢?
考虑到我们之间的建图有个 b u g bug bug,那就是 ( u , v a l 1 u , i ≤ t ) (u,val1_{u,i\le t}) (u,val1u,it)全部都可以转移给 ( v , q ) (v,q) (v,q),但是我们只转移了 ( u , v a l 1 u , v a l u , t ) (u,val1_{u,val_{u,t}}) (u,val1u,valu,t)于是凉凉。

直接暴力建边好像复杂度 O ( m 2 ) O(m^2) O(m2)了啊。。。
于是考虑连边 ( u , v a l 1 u , i ) → ( u , v a l 1 u , i + 1 ) (u,val1_{u,i})\rightarrow(u,val1_{u,i+1}) (u,val1u,i)(u,val1u,i+1)
边权怎么弄???
假设我们现在有这两条边 ( u , a ) → ( u , b ) → ( v , c ) (u,a)\rightarrow(u,b)\rightarrow(v,c) (u,a)(u,b)(v,c)
那么本来应该是 ( u , a ) → ( v , c )   a n d   ( u , b ) → ( v , c ) (u,a)\rightarrow(v,c)\ and\ (u,b)\rightarrow(v,c) (u,a)(v,c) and (u,b)(v,c)
考虑两个之间的差量,不妨设这条边为 ( u , v , t , c ) (u,v,t,c) (u,v,t,c)
那么
( u , a ) → ( v , c ) (u,a)\rightarrow(v,c) (u,a)(v,c)边权是 A ( c − a ) 2 + B ( c − a ) + C A(c-a)^2+B(c-a)+C A(ca)2+B(ca)+C
( u , b ) → ( v , c ) (u,b)\rightarrow(v,c) (u,b)(v,c)边权是 A ( c − b ) 2 + B ( c − b ) + C A(c-b)^2+B(c-b)+C A(cb)2+B(cb)+C
做个差发现差量是 A ( a 2 − b 2 ) + B ( b − a ) + c ∗ ( 2 A ( b − a ) ) A(a^2-b^2)+B(b-a)+c*(2A(b-a)) A(a2b2)+B(ba)+c(2A(ba))
很容易把这个结论拓展到多个点的情况。
然后把 c c c看成一个变量,相当于是一堆 A ′ + B ′ c A'+B'c A+Bc取最小值,这很凸包。
我们把 ( u , b ) (u,b) (u,b)连出去的所有点按照这个 t t t排序,把 ( u , x 1 ) , ( u , x 2 ) , . . . , ( u , b ) (u,x_1),(u,x_2),...,(u,b) (u,x1),(u,x2),...,(u,b)对应的二元组拿来建个凸包就行啦。
代码:

#include
#define ri register int
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
typedef pair<ll,ll> pll;
const int N=2e5+5,M=4e5+5,K=1005;
int n,m,A,B,C,tot=0;
struct Node{
	int v;pll w;
	friend inline bool operator<(const Node&a,const Node&b){return a.w.fi>b.w.fi;}
};
struct edge{int u,v,p,q;}E[M];
Node trans[M<<1];
bool oktrans[M<<1];
ll dis[M<<1];
vector<Node>e[M<<1];
set<int>vis[K],tim[N];
vector<pll>a[M<<1];
typedef set<int>::iterator It;
inline pll operator+(const pll&a,const pll&b){return pll(a.fi+b.fi,a.se+b.se);}
struct pot{
	ll x,y;
	pot(ll x=0,ll y=0):x(x),y(y){}
	friend inline pot operator-(const pot&a,const pot&b){return pot(a.x-b.x,a.y-b.y);}
	friend inline ll operator^(const pot&a,const pot&b){return a.x*b.y-a.y*b.x;}
}ap[K<<1];
int top,q[K<<1],mxtim=0;
inline void build(vector<pll>a){
	top=0;
	int m=a.size();
	for(ri i=0;i<m;++i)ap[i+1]=pot(a[i].se,a[i].fi);
	for(ri i=1;i<=m;++i){
		while(top>1&&((ap[i]-ap[q[top]])^(ap[q[top]]-ap[q[top-1]]))>=0)--top;
		q[++top]=i;
	}
	for(ri i=1;i<=top;++i)ap[i]=ap[q[i]];
}
inline ll calc(pot a,ll b){return a.x*b+a.y;}
inline bool operator<(const pii&a,const pii&b){return a.se>b.se;}
const int mogic=1e6+7;
inline bool operator==(const pii&a,const pii&b){return a.fi==b.fi&&a.se==b.se;}
struct Hash_table1{
	vector<pii>ori[mogic];
	vector<int>val[mogic];
	inline void update(pii x,int c){
		int t=(x.fi*1000+x.se)%mogic;
		ori[t].push_back(x);
		val[t].push_back(c);
	}
	inline int query(pii x){
		int t=(x.fi*1000+x.se)%mogic;
		for(ri i=ori[t].size();~i;--i)if(ori[t][i]==x)return val[t][i];
	}
}idx;
struct Hash_table2{
	vector<int>ori[mogic];
	vector<pii>val[mogic];
	inline void update(int x,pii c){
		int t=x%mogic;
		ori[t].push_back(x);
		val[t].push_back(c);
	}
	inline pii query(int x){
		int t=x%mogic;
		for(ri i=ori[t].size();~i;--i)if(ori[t][i]==x)return val[t][i];
	}
}invidx;
bool in[N];
inline void bfs(){
	ll ans=1e18;
	for(ri i=0;i<=tot;++i)dis[i]=1e18;
	dis[1]=0;
	static int pre[N];
	for(ri tt=0;tt<=mxtim;++tt){
		if(!vis[tt].size())continue;
		for(It it=vis[tt].begin();it!=vis[tt].end();++it){
			pii p=pii(*it,tt);
			int id=idx.query(p);
			if(p.fi==n){
				ans=min(ans,dis[id]+tt);
				continue;
			}
			if(oktrans[id]){
				int v=trans[id].v;
				pll w=trans[id].w;
				if(a[id].size()&&dis[id]<=a[id][0].fi)a[v].push_back(w+pll(dis[id],0));
				a[v].push_back(w+pll(dis[id],0));
				ri i;
				for(i=0;i<a[id].size()&&a[id][i].fi>=dis[id];++i);
				for(;i<a[id].size();++i)a[v].push_back(w+a[id][i]);
			}
			sort(e[id].begin(),e[id].end());
			build(a[id]);
			for(ri cur=1,i=0,v,P,w;i<e[id].size();++i){
				v=e[id][i].v;
				P=e[id][i].w.fi;
				w=e[id][i].w.se;
				if(dis[v]>dis[id]+w)pre[v]=id;
				dis[v]=min(dis[v],dis[id]+w);
				while(cur<top&&calc(ap[cur],P)>calc(ap[cur+1],P))++cur;
				if(top)dis[v]=min(dis[v],calc(ap[cur],P)+w);
			}
		}
	}
	cout<<ans<<'\n';
}
signed main(){
	n=read(),m=read(),A=read(),B=read(),C=read();
	vis[0].insert(1),tim[1].insert(0),idx.update(pii(1,0),tot=1),invidx.update(tot,pii(1,0));
	for(ri i=1,u,v,p,q;i<=m;++i){
		u=read(),v=read(),p=read(),q=read();
		E[i]=(edge){u,v,p,q};
		mxtim=max(mxtim,q);
		if(!vis[q].count(v))vis[q].insert(v),tim[v].insert(q),++tot,idx.update(pii(v,q),tot),invidx.update(tot,pii(v,q));
	}
	for(ri u,v,x,y,i=1;i<n;++i){
		if(tim[i].size()<2)continue;
		for(It il=tim[i].begin(),ir=++tim[i].begin();ir!=tim[i].end();++il,++ir){
			x=*il,y=*ir;
			u=idx.query(pii(i,x)),v=idx.query(pii(i,y));
			trans[u]=(Node){v,pll((ll)B*(y-x)+(ll)A*(x*x-y*y),2ll*A*(y-x))};
			oktrans[u]=1;
		}
	}
	for(ri u,v,p,q,i=1;i<=m;++i){
		u=E[i].u,v=E[i].v,p=E[i].p,q=E[i].q;
		if(!tim[u].size())continue;
		It it=tim[u].lower_bound(p);
		if(p<*tim[u].begin())continue;
		if(it==tim[u].end()||*it>p)--it;
		e[idx.query(pii(u,*it))].push_back((Node){idx.query(pii(v,q)),pll(p,(ll)A*(p-*it)*(p-*it)+(ll)B*(p-*it)+(ll)C)});
	}
	bfs();
	return 0;
}

你可能感兴趣的:(#,前缀和,#,最短路,#,凸包)