带权有向图,支持一下操作:
- 询问(1)到某个点(v)的最短路。
- 读入一个边集,将这些边的边权都加(1)。
(n,mle 10^5,Qle 2000)
正解可以猜到是(O(mQ))级别的。
如果最大距离为(W),可以用(O(w))大小的桶来优化dijkstra,做到(O(m+W))的时间。
注意到每次边权的变化量都很小,于是(Delta wle 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
",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;
}