【JZOJ3773】【NOI2015模拟8.15】小 P 的烦恼

来源:互联网 发布:黄药师软件使用方法 编辑:程序博客网 时间:2024/05/22 06:56

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 longusing 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);    }}
原创粉丝点击