Description
问题是这样的,高代老师近期要组织班上同学一起去漂流,漂流可以看做是在一张 n 个点 m 条边的有向无环图上进行的,点编号从 0 到 n-1 ,表示景点; 边是连接各景点的一定长度的河道。同时,定义编号为 s 是起点而 t 是终点。我们不妨把从 s 点到 t 点不论走什么样的路径都需要经过的边称为桥, 这些桥由于地势险要所以是危险的。现在高代老师有两条长度为 l 的安全绳,他希望用这两条安全绳覆盖尽可能长的桥,使得他们通过的桥的长度之和尽量短。
绳子可以覆盖普通的边,不一定只覆盖一条边
对于 100%的数据,n<=100000, m<=200000,0<=s,t,si,ti
Analysis
比赛想到正解没时间写系列
结果我dfs的时候在9万9千多爆栈,TM的n最大10w,各种脏话上脑。。。。。
可以将所有的桥弄出来,比较简单的算法可以用拓扑序弄出走到某个点的方案数,也就弄出了走某条边的方案数
如果走某条边的方案数=从st到en的方案数,那么边为桥
然后是一个线段覆盖(桥是线段,需要被绳子覆盖)模型,考虑绳子可能放在哪些位置
显然只可能放在线段两个端点
如果从左到右枚举,右边绳子放的位置(必定是某条线段右端点,且方向为左)呢
另一条绳子的取值可以用指针移动来搞,甚至可以弄到线性
整题线性解决
Code
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
#define efo(i,v) for(int i=last[v];i;i=next[i])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define mset(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
void read(int &n)
{
n=0;char ch;int p=1;
for(ch=getchar();ch<'0' || '9'<ch;ch=getchar())
if(ch=='-') p=-1;
for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';
n*=p;
}
const int N=1e5+5,M=2e5+5,mo=1e9+7;
const ll INF=1e17;
int n,m,num,st,en,L,tot,to[M],next[M],wei[M],last[N],in[N],out[N];
int fto[M],fnext[M],flast[N],sm[N];
int ans,qi[N],pmx[N];
ll dis[N],f[N],g[N];
struct node
{
int x,y;
}a[N];
bool cmp(node a,node b)
{
return a.x<b.x;
}
bool bz[N];
struct edge
{
int u,v,w;
}b[M];
queue<int> q;
void link(int u,int v,int w)
{
to[++tot]=v,next[tot]=last[u],wei[tot]=w,last[u]=tot;
fto[tot]=u,fnext[tot]=flast[v],flast[v]=tot;
}
void pre()
{
fo(i,0,n) dis[i]=INF;
mset(f,0);mset(g,0);
dis[st]=0,f[st]=1;
for(q.push(st);!q.empty();q.pop())
{
int u=q.front();
efo(i,u)
{
int v=to[i];
dis[v]=min(dis[v],dis[u]+wei[i]);
f[v]=(f[v]+f[u])%mo;
if(!--in[v]) q.push(v);
}
}
mset(bz,0);
g[en]=1;
for(q.push(en);!q.empty();q.pop())
{
int u=q.front();
for(int i=flast[u];i;i=fnext[i])
{
int v=fto[i];
g[v]=(g[v]+g[u])%mo;
if(!--out[v]) q.push(v);
}
}
qi[0]=0;
fo(i,1,m)
{
int u=b[i].u,v=b[i].v;
if(f[en]==f[u]*g[v]%mo) qi[++qi[0]]=i;
}
}
void work()
{
num=0;
mset(a,0);
fo(j,1,qi[0])
{
int i=qi[j];
a[++num].x=dis[b[i].u],a[num].y=dis[b[i].v];
if(a[num].x>a[num].y) swap(a[num].x,a[num].y);
}
sort(a+1,a+num+1,cmp);
mset(sm,0);
fo(i,1,num) sm[i]=sm[i-1]+a[i].y-a[i].x;
mset(pmx,0);
ans=0;
int l=1,k=0,j=0;
fo(i,1,num)
{
while(a[i].y-a[l].x>L && l<=num) l++;
int t=sm[i]-sm[l-1]+min(a[l-1].y-a[l-1].x,max(0,L-(a[i].y-a[l-1].y)));
pmx[i]=max(pmx[i-1],t);
int pos=a[i].y-L,rs=0;
while(a[k+1].x<=pos && k<num) k++;
if(k)
{
if(pos-a[k].x>=L) rs=L;
else
{
if(a[k].y<=pos) rs=max(rs,pmx[k]);
else
{
while(pos-a[j].x>L && j<=num) j++;
rs=pos-a[k].x+sm[k-1]-sm[j-1];
rs+=min(a[j-1].y-a[j-1].x,max(0,L-(pos-a[j-1].y)));
rs=max(rs,pmx[k-1]);
}
}
}
ans=max(ans,t+rs);
}
}
int main()
{
int u,v,w,T;
read(T);
while(T--)
{
tot=0;mset(last,0);mset(flast,0);mset(in,0);mset(out,0);
read(n),read(m),read(st),read(en),read(L);
fo(i,1,m)
{
read(u),read(v),read(w);
b[i].u=u,b[i].v=v,b[i].w=w;in[v]++,out[u]++;
link(u,v,w);
}
pre();
if(dis[en]==INF){printf("-1\n");continue;}
work();
printf("%d\n",sm[num]-ans);
}
return 0;
}