传送门
解析:
首先本题数据不是DAG。。。对的就是数据有误
不然有更加优秀的做法。。。
思路:
必经边是吧,那就化边为点建立支配树。
跑最短路,因为我们要覆盖。。
然后我们把所有必经边取出来DP出前缀和后缀单条最大值,
然后考虑两条在某一个端点重合,再来一次DP。
然后统计一下答案和剩余的必经边的权值。
完了。
如果是DAG的话判断必经边可以做到 O ( n + m ) O(n+m) O(n+m)而不是 L e n g a u e r − T a r j a n Lengauer-Tarjan Lengauer−Tarjan的 O ( ( n + m ) log n ) O((n+m)\log n) O((n+m)logn)。我们只需要正反拓扑序DP记录一下 S S S和 T T T到每个点的方案数。枚举每条边,如果 c n t S u × c n t T v = = c n t S T cntS_u\times cntT_v==cntS_T cntSu×cntTv==cntST那么这条边就是必经边了。
DAG的代码我放最下面了,自己造DAG对拍了一个多小时,应该没有问题。
如果你对拍出问题,请告知博主,谢谢!
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const
namespace IO{
namespace IOONLY{
cs int Rlen=1<<20|1;
char buf[Rlen],*p1,*p2;
}
inline char get_char(){
using namespace IOONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=300005;
int n,m,S,T,L;
vector<int> g[N],revg[N];
int val[N];
int dist[N];
inline void Dij(){
memset(dist,0x3f,sizeof(int)*(m+n+1));
set<pair<int,int> > q;
q.insert(make_pair(dist[S]=0,S));
while(!q.empty()){
int u=q.begin()->second;
q.erase(q.begin());
for(int re e=0,v;e<g[u].size();++e){
v=g[u][e];
if(dist[v]>dist[u]+val[v]){
q.erase(make_pair(dist[v],v));
dist[v]=dist[u]+val[v];
q.insert(make_pair(dist[v],v));
}
}
}
}
int dfn[N],id[N],fa[N],dfs_clock;
void dfs(int u){
id[dfn[u]=++dfs_clock]=u;
for(int re e=0,v;e<g[u].size();++e){
v=g[u][e];
if(dfn[v])continue;
fa[v]=u;dfs(v);
}
}
stack<int,vector<int> > dom[N];
int bel[N],nd[N],semi[N],idom[N];
inline int getfa(int x){
if(x==bel[x])return x;
int tmp=getfa(bel[x]);
if(dfn[semi[nd[bel[x]]]]<dfn[semi[nd[x]]])nd[x]=nd[bel[x]];
return bel[x]=tmp;
}
inline void tarjan(){
for(int re i=dfs_clock,u;i>1;--i){
u=id[i];
for(int re e=0,v;e<revg[u].size();++e){
v=revg[u][e];
if(!dfn[v])continue;
getfa(v);
if(dfn[semi[nd[v]]]<dfn[semi[u]])semi[u]=semi[nd[v]];
}
dom[semi[u]].push(u);
u=bel[u]=fa[u];
while(!dom[u].empty()){
int v=dom[u].top();dom[u].pop();
getfa(v);
if(semi[nd[v]]==u)idom[v]=u;
else idom[v]=nd[v];
}
}
for(int re i=2,u;i<=dfs_clock;++i){
u=id[i];
if(semi[u]^idom[u])idom[u]=idom[idom[u]];
}
}
int q[N],qn;
int pre[N],suf[N];
inline void solve(){
n=getint();m=getint();
S=getint()+1;T=getint()+1;
L=getint();
for(int re i=1;i<=m;++i){
int u=getint()+1,v=getint()+1;
g[u].push_back(i+n);revg[i+n].push_back(u);
g[i+n].push_back(v);revg[v].push_back(i+n);
val[i+n]=getint();
}
dfs(S);if(dfn[T]==0){puts("-1");return ;}
for(int re i=1;i<=n+m;++i)nd[i]=semi[i]=bel[i]=i;
tarjan();
Dij();
qn=0;
for(int re u=T;u^S;u=idom[u])if(u>n)q[++qn]=u;
q[qn+1]=0;
for(int re l=1,r=1,tmp=0;r<=qn;++r){
tmp+=l==r?0:val[q[r]];
while(dist[q[l]]-dist[q[r]]+val[q[r]]-val[q[l]]>L)tmp-=val[q[++l]];
int len=tmp+min(L-(dist[q[l]]-dist[q[r]]+val[q[r]]-val[q[l]]),val[q[l]]);
pre[r]=max(pre[r-1],len);
}
suf[qn+1]=0;
for(int re l=qn,r=qn,tmp=0;l;--l){
tmp+=l==r?0:val[q[l]];
while(dist[q[l]]-dist[q[r]]>L)tmp-=val[q[--r]];
int len=tmp+min(L-(dist[q[l]]-dist[q[r]]),val[q[r]]);
suf[l]=max(suf[l+1],len);
}
int ans=0;
for(int re i=1;i<=qn+1;++i)ans=max(ans,pre[i-1]+suf[i]);
L<<=1;
for(int re l=qn,r=qn,tmp=0;l;--l){
tmp+=l==r?0:val[q[l]];
while(dist[q[l]]-dist[q[r]]>L)tmp-=val[q[--r]];
int len=tmp+min(L-(dist[q[l]]-dist[q[r]]),val[q[r]]);
suf[l]=max(suf[l+1],len);
}
ans=-max(ans,suf[1]);
for(int re i=1;i<=qn;++i)ans+=val[q[i]];
printf("%d\n",ans);
}
inline void init(){
for(int re i=1;i<=n+m;++i){
val[i]=dfn[i]=0;
g[i].clear();
revg[i].clear();
}
dfs_clock=0;
}
signed main(){
for(int re T=getint();T--;)init(),solve();
return 0;
}
代码( D A G DAG DAG):
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc putchar
#define cs const
namespace IO{
namespace IOONLY{
cs int Rlen=1<<20|1;
char buf[Rlen],*p1,*p2;
}
inline char get_char(){
using namespace IOONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=100005;
vector<int> g[N],rg[N];
vector<int> w[N];
int deg[N],rdeg[N];
int n,m,S,T,L;
cs ll mod=9999999999999937;
inline ll add(ll a,ll b){return a+b>=mod?a+b-mod:a+b;}
inline ll mul(ll a,ll b){return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;}
ll cntS[N],cntT[N];
int dfnS[N],dfnT[N];
int idS[N],idT[N];
inline void topsort(int S,vector<int> *edge,ll *cnt,int *du,int *dfn,int *id){
cnt[S]=1;
queue<int> q;
re int topsort_clock=0;
for(int re i=1;i<=n;++i)if(!du[i])q.push(i);
while(!q.empty()){
re int u=q.front();q.pop();
id[dfn[u]=++topsort_clock]=u;
for(int re e=0,v;e<edge[u].size();++e){
v=edge[u][e];
cnt[v]=add(cnt[v],cnt[u]);
if(!(--du[v]))q.push(v);
}
}
// assert(topsort_clock==n);
}
int dist[N];
inline void Dij(){
memset(dist+1,0x3f,sizeof(int)*n);
set<pair<int,int> > q;
q.insert(make_pair(dist[S]=0,S));
while(!q.empty()){
re int u=q.begin()->second;
q.erase(q.begin());
for(int re e=0,v;e<g[u].size();++e){
v=g[u][e];
if(dist[v]>dist[u]+w[u][e]){
q.erase(make_pair(dist[v],v));
dist[v]=dist[u]+w[u][e];
q.insert(make_pair(dist[v],v));
}
}
}
}
int dis[N],val[N],qn;
int pre[N],suf[N];
inline void solve(){
n=getint();m=getint();
S=getint()+1;T=getint()+1;
L=getint();
for(int re i=1;i<=m;++i){
int u=getint()+1,v=getint()+1,val=getint();
g[u].push_back(v);++deg[v];
rg[v].push_back(u);++rdeg[u];
w[u].push_back(val);
}
topsort(S,g,cntS,deg,dfnS,idS);if(cntS[T]==0){puts("-1");return ;}
topsort(T,rg,cntT,rdeg,dfnT,idT);
Dij();qn=0;
for(int re i=dfnT[T]+1;i<=dfnT[S];++i){
int u=idT[i];
if(dfnS[S]<=dfnS[u]&&dfnS[u]<=dfnS[T]&&cntS[u]&&cntT[u]){
for(int re e=0,v;e<g[u].size();++e){
v=g[u][e];
if(mul(cntS[u],cntT[v])==cntS[T]){
dis[++qn]=dist[u];
val[qn]=w[u][e];
break;
}
}
}
}
dis[qn+1]=0;val[qn+1]=0;
for(int re l=1,r=1,tmp=0;r<qn;++r){
tmp+=l==r?0:val[r];
while(dis[l]-dis[r]+val[r]-val[l]>L)tmp-=val[++l];
int len=tmp+min(L-(dis[l]-dis[r]+val[r]-val[l]),val[l]);
pre[r]=max(pre[r-1],len);
}
suf[qn+1]=0;
for(int re l=qn,r=qn,tmp=0;l;--l){
tmp+=l==r?0:val[l];
while(dis[l]-dis[r]>L)tmp-=val[--r];
int len=tmp+min(L-(dis[l]-dis[r]),val[r]);
suf[l]=max(suf[l+1],len);
}
int ans=0;
for(int re i=1;i<=qn+1;++i)ans=max(ans,pre[i-1]+suf[i]);
L<<=1;
for(int re l=qn,r=qn,tmp=0;l;--l){
tmp+=l==r?0:val[l];
while(dis[r]-dis[l]>L)tmp-=val[--r];
int len=tmp+min(L-(dis[l]-dis[r]),val[r]);
suf[l]=max(suf[l+1],len);
}
ans=-max(ans,suf[1]);
for(int re i=1;i<=qn;++i)ans+=val[i];
printf("%d\n",ans);
}
inline void init(){
for(int re i=1;i<=n;++i){
g[i].clear();rg[i].clear();
w[i].clear();
cntS[i]=cntT[i]=0;
dfnS[i]=dfnT[i]=0;
}
}
signed main(){
for(int re T=getint();T--;)init(),solve();
return 0;
}