CF843D Dynamic Shortest Path

带权有向图,支持一下操作:

  1. 询问\(1\)到某个点\(v\)的最短路。
  2. 读入一个边集,将这些边的边权都加\(1\)

\(n,m\le 10^5,Q\le 2000\)


正解可以猜到是\(O(mQ)\)级别的。

如果最大距离为\(W\),可以用\(O(w)\)大小的桶来优化dijkstra,做到\(O(m+W)\)的时间。

注意到每次边权的变化量都很小,于是\(\Delta w\le n-1\)

用改边权的套路来把\(W\)缩小:先跑一边普通的最短路求出\(dis_i\),然后将边\((u,v,w)\)\(w\)改成\(dis_u+w-dis_v\)。由三角形不等式得修改后边权仍然非负。

现在对边权进行修改,然后再跑最短路,这时候跑出来的\(dis'_i\)表示\(dis_i\)的增加量。

由于一定有\(dis_i'\le n-1\),所以每次时间是\(O(m+n)\)

跑完之后继续更新边权即可。


using namespace std;
#include <bits/stdc++.h>
#define N 100005
#define ll long long
#define mp(x,y) make_pair(x,y)
#define fi first
#define se second
#define INF 100000000000000
int n,m;
struct EDGE{
	int to,w;
	EDGE *las;
} e[N];
int ne;
EDGE *last[N];
void link(int u,int v,int w){
	e[ne]={v,w,last[u]};
	last[u]=e+ne++;
}
ll dis[N],f[N];
void adjust(){
	for (int i=1;i<=n;++i)
		for (EDGE *ei=last[i];ei;ei=ei->las)
			ei->w+=dis[i]-dis[ei->to];
	for (int i=1;i<=n;++i)
		f[i]+=dis[i];
}
void SP0(){
	typedef pair<ll,int> info;
	static priority_queue<info,vector<info>,greater<info> > q;
	memset(dis,127,sizeof(ll)*(n+1));
	dis[1]=0;
	q.push(mp(0,1));
	while (!q.empty()){
		int x=q.top().se;
		ll s=q.top().fi;
		q.pop();
		if (s!=dis[x])
			continue;
		for (EDGE *ei=last[x];ei;ei=ei->las)
			if (s+ei->w<dis[ei->to]){
				dis[ei->to]=s+ei->w;
				q.push(mp(dis[ei->to],ei->to));
			}
	}
	adjust();
}
void SP1(){
	static vector<int> b[N];
	memset(dis,127,sizeof(ll)*(n+1));
	dis[1]=0;
	b[0].push_back(1);
	for (int i=0;i<n;++i){
		for (int j=0;j<b[i].size();++j){
			int x=b[i][j];
			if (dis[x]<i)
				continue;
			for (EDGE *ei=last[x];ei;ei=ei->las)
				if (i+ei->w<n && i+ei->w<dis[ei->to]){
					dis[ei->to]=i+ei->w;
					b[dis[ei->to]].push_back(ei->to);
				}
		}
		b[i].clear();
	}
	adjust();
}
int main(){
//	freopen("in.txt","r",stdin);
	int Q;
	scanf("%d%d%d",&n,&m,&Q);
	for (int i=0;i<m;++i){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		link(u,v,w);
	}
	SP0();
	while (Q--){
		int op;
		scanf("%d",&op);
		if (op==1){
			int v;
			scanf("%d",&v);
			printf("%lld\n",dis[v]>INF?-1:f[v]);
		}
		else{
			int c;
			scanf("%d",&c);
			for (int i=0;i<c;++i){
				int id;
				scanf("%d",&id),--id;
				e[id].w++;
			}
			SP1();
		}
	}
	return 0;
}
posted @ 2021-02-22 22:50  jz_597  阅读(84)  评论(0编辑  收藏  举报