Description
小 P 最近遇上了大麻烦,他的高等代数挂科了。于是他只好找高代老师求情。善良的高代老师答应不挂他,但是要求小 P 帮助他一起解决一个难题。
问题是这样的,高代老师近期要组织班上同学一起去漂流,漂流可以看做是在一张 n 个点 m 条边的有向无环图上进行的,点编号从 0 到 n-1 ,表示景点; 边是连接各景点的一定长度的河道。同时,定义编号为 s 是起点而 t 是终点。我们不妨把从 s 点到 t 点不论走什么样的路径都需要经过的边称为桥, 这些桥由于地势险要所以是危险的。现在高代老师有两条长度为 l 的安全绳,他希望用这两条安全绳覆盖尽可能长的桥,使得他们通过的桥的长度之和尽量短。
Data Constraint
对于 10%的数据,n<=10,m<=20
对于 30%的数据,n<=1000,m<= 10000
对于 100%的数据,n<=100000, m<=200000,0<=s,t,si,ti
Solution
这道题的关键是求桥。由于图是一个DAG,我们可以拓扑一遍原图,将s到每个点的方案记录下来,然后倒着拓扑一遍,记录t到每个点的方案,若一条有向边u-v满足起点到u的方案*v到终点的方案=s到t的方案,则u-v必为桥边,证明显然(因为这说明不存在其他不经过u-v而从s-t的路径)
然后在跑拓扑的时候我们顺便跑出个最短路,桥边必然在最短路上,然后问题就变成在一条路径上覆盖两条长度为len的绳子,贪心放一下O(N)解决。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=2e5+5,mo=1e9+7;
ll fa[maxn],fa1[maxn],d[maxn],bz[maxn],first[maxn],last[maxn],next[maxn],value[maxn],v[maxn*20];
ll p[maxn],q[maxn],f[maxn],g[maxn],first1[maxn],last1[maxn],next1[maxn];
ll n,m,i,t,j,k,l,x,y,z,test,s,st,len,num,tot,len1,sum,mx,ans;
void lian(int x,int y,int z){
last[++num]=y;next[num]=first[x];first[x]=num;value[num]=z;
}
void lian1(int x,int y){
last1[num]=y;next1[num]=first1[x];first1[x]=num;
}
void spfa(){
int i=0,j=1;v[1]=s;memset(d,127,sizeof(d));memset(bz,0,sizeof(bz));
d[s]=0;bz[s]=1;
while (i<j){
x=v[++i];
for (t=first[x];t;t=next[t]){
if (d[x]+value[t]>=d[last[t]]) continue;
d[last[t]]=d[x]+value[t];fa[last[t]]=x;fa1[last[t]]=t;
if (!bz[last[t]])v[++j]=last[t],bz[v[j]]=1;
}
bz[x]=0;
}x=st;d[0]=0;
if (d[st]>1e9){
d[0]=-1;return;
}
while (x!=s) d[++d[0]]=fa1[x],x=fa[x];
}
void make(){
v[0]=0;j=0;
for (i=0;i<n;i++)
if (!p[i]) v[++j]=i;
f[s]=1;i=0;
while (i<j){
x=v[++i];
for (t=first[x];t;t=next[t]){
f[last[t]]=(f[last[t]]+f[x])%mo;
p[last[t]]--;
if (!p[last[t]]) v[++j]=last[t];
}
}
}
void make1(){
v[0]=0;j=0;
for (i=0;i<n;i++)
if (!q[i]) v[++j]=i;
g[st]=1;i=0;
while (i<j){
x=v[++i];
for (t=first1[x];t;t=next1[t]){
g[last1[t]]=(g[last1[t]]+g[x])%mo;
q[last1[t]]--;
if (!q[last1[t]]) v[++j]=last1[t];
}
}
}
int dg(int sum,int j,int tot,int len1,int x){
while(sum>x){
if (sum-tot>x) sum-=tot,len1-=tot*bz[d[j]],j--,tot=value[d[j]];
else t=x-(sum-tot),sum-=tot-t,len1-=(tot-t)*bz[d[j]],tot=t;
}
return len1;
}
int main(){
// freopen("data.in","r",stdin);//freopen("data.out","w",stdout);
scanf("%d",&test);
while (test){test--;
memset(first,0,sizeof(first));memset(first1,0,sizeof(first1));num=0;ans=0;
memset(p,0,sizeof(p));memset(q,0,sizeof(q));memset(f,0,sizeof(f));memset(g,0,sizeof(g));
scanf("%d%d%d%d%d",&n,&m,&s,&st,&len);
for (i=1;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),lian(x,y,z),lian1(y,x),p[y]++,q[x]++;
spfa();
if (d[0]==-1){
printf("-1\n");
continue;
}
make();
make1();
for (i=0;i<n;i++)
for (t=first[i];t;t=next[t])
if (f[i]*g[last[t]]%mo==f[st]) bz[t]=1;
len1=0;sum=0;j=1;tot=value[d[1]];f[0]=0;g[0]=0;
for (i=1;i<=d[0];i++){
if (sum+value[d[i]]<=len) sum+=value[d[i]],g[i]=len1,p[i]=value[d[i]],len1+=p[i]*bz[d[i]];
else{
if (value[d[i]]<=len){
g[i]=len1;p[i]=len-sum;
while(sum+value[d[i]]>len){
if (sum+value[d[i]]-tot>len) sum-=tot,len1-=tot*bz[d[j]],j++,tot=value[d[j]];
else t=len-(sum+value[d[i]]-tot),sum-=tot-t,len1-=(tot-t)*bz[d[j]],tot=t;
}
sum+=value[d[i]];len1+=value[d[i]]*bz[d[i]];
}else sum=len,len1=len*bz[d[i]],tot=len,j=i,g[i]=0,p[i]=len;
}
f[i]=max(f[i-1],len1);
while (!bz[d[j]] && j<=i) sum-=tot,j++,tot=value[d[j]];
}
len1=0;sum=0;j=d[0];tot=value[d[d[0]]];mx=0;
for (i=d[0];i>=1;i--){
if (sum+value[d[i]]<=len) sum+=value[d[i]],len1+=value[d[i]]*bz[d[i]],t=len1;
else{
if (bz[d[i]]&&p[i]){
if (p[i]+len-sum>=value[d[i]])ans=max(ans,len1+g[i]+value[d[i]]);
else{
if (len>=value[d[i]]-p[i]){
t=dg(sum,j,tot,len1,len-value[d[i]]+p[i]);
ans=max(ans,t+g[i]+value[d[i]]);
}else ans=max(ans,len1+g[i]+p[i]+len-sum);
}
}
if (value[d[i]]<=len){
while(sum+value[d[i]]>len){
if (sum+value[d[i]]-tot>len) sum-=tot,len1-=tot*bz[d[j]],j--,tot=value[d[j]];
else t=len-(sum+value[d[i]]-tot),sum-=tot-t,len1-=(tot-t)*bz[d[j]],tot=t;
}
sum+=value[d[i]];len1+=value[d[i]]*bz[d[i]];
}else sum=len,len1=len*bz[d[i]],j=i,tot=len;
}
mx=max(mx,len1);
ans=max(ans,f[i-1]+mx);
while (!bz[d[j]] && j>=i) sum-=tot,j--,tot=value[d[j]];
}t=0;
for (i=1;i<=d[0];i++)
t+=bz[d[i]]*value[d[i]];
ans=t-ans;
printf("%d\n",ans);
}
}