前言
多写写构造题是有好处的
题目
讲解
我们首先考虑无解
对于每条不确定的边,我们令它们的权值为(1)
如果此时最短路的结果大于(L),无解
等于(L)可直接输出
现在我们考虑如何让最短路从一个比(L)小的值变为(L)
我们记(L)与这个值的差为(ADD)
我们要做的就是让(s)到(t)的最短路增加(ADD)
这样貌似不太好想,但是如果让所有点全部加上(ADD)呢?
豁然开朗!
我们直接在跑(dij)的时候
对于每条可修改边增加权值,当然这个值是可以直接算出来的
如果通过这样的操作都不是(L),输出(NO)
代码
int tot;
int U[MAXM],V[MAXM],head[MAXN];
LL W[MAXM];
bool c[MAXM];
struct edge
{
int v,ID,nxt;
}e[MAXM << 1];
void Add_Edge(int x,int y,int ID)
{
e[++tot].v = y;
e[tot].nxt = head[x];
e[tot].ID = ID;
head[x] = tot;
}
void Add_Double_Edge(int x,int y,int ID)
{
Add_Edge(x,y,ID);
Add_Edge(y,x,ID);
}
LL dis[2][MAXN];
struct node
{
int x;
LL val;
node(){}
node(int x1,LL val1){
x = x1;
val = val1;
}
bool operator < (const node &px)const{
return val > px.val;
}
};
LL ADD;
void dij(int x)
{
for(int i = 0;i < n;++ i) dis[x][i] = INF;
priority_queue<node> q;
q.push(node(s,dis[x][s] = 0));
while(!q.empty())
{
node t = q.top(); q.pop();
if(t.val > dis[x][t.x]) continue;
for(int i = head[t.x]; i ;i = e[i].nxt)
{
if(!x && t.val + W[e[i].ID] < dis[x][e[i].v])
q.push(node(e[i].v,dis[x][e[i].v] = t.val + W[e[i].ID]));
if(x)
{
if(c[e[i].ID]) W[e[i].ID] += Max(0ll,ADD - (t.val + W[e[i].ID] - dis[0][e[i].v]));
if(t.val + W[e[i].ID] < dis[x][e[i].v]) q.push(node(e[i].v,dis[x][e[i].v] = t.val + W[e[i].ID]));
}
}
}
}
void NO()
{
printf("NO");
exit(0);
}
void print()
{
printf("YES
");
for(int i = 1;i <= m;++ i)
{
Put(U[i],' ');
Put(V[i],' ');
Put(W[i],'
');
}
exit(0);
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); m = Read(); L = Read(); s = Read(); t = Read();
for(int i = 1;i <= m;++ i)
{
U[i] = Read();
V[i] = Read();
W[i] = Read();
if(!W[i]) c[i] = 1,W[i] = 1;
Add_Double_Edge(U[i],V[i],i);
}
dij(0);
if(dis[0][t] > L) NO();
else if(dis[0][t] == L) print();
ADD = L - dis[0][t];
dij(1);
if(dis[1][t] < L) NO();
print();
return 0;
}