[2017纪中10-27]图 分治+DP

来源:互联网 发布:网络监控摄像头序列号 编辑:程序博客网 时间:2024/05/21 16:33

题面
首先发现总左往右考虑l到r的边,从u走到v的最小代价,相当于从右往左考虑r到l的边,从v走到u的最小代价。
于是支持从某条边向两边拓展,考虑离线分治。
假设当前在处理分治区间[L,R],设 mid=(L+R)/2,询问区间跨过了 mid 的询问就可以求解,用 DP 得到 lef[i][x][y]表示从 x 出发,处理了从 i 到 mid 的边之后到达 y 的最小代价,以及 rig[i][x][y]表示从 x 出发,处理了从 mid+1 到 i 的边之后到达 y 的最小代价,那么查询的时候只要枚举一下中间经过的那个点就好了。
注意lef是从右往左考虑的,lef[i][x][y]应该转移y到x最小代价。
时间复杂度 O(qn+q log m +m log m *n^2)。
代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define ll long long#define chkmin(a,b) a=min(a,b)using namespace std;const int maxm=20010;const int maxq=200010;int n,m,numq;ll lef[maxm][35][35],rig[maxm][35][35],sr[maxm];struct node1{    int x,y,c,r;}e[maxm];struct node2{    int s,t,l,r,id;    ll ans;}q[maxq],nq[maxq];bool cmp(node2 a,node2 b){    return a.id<b.id;}int read(){    int x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}    return x;}void solve(int L,int R,int lx,int rx){    if(lx>rx||L>R) return ;     int mid=(L+R)>>1,d0,d1,tot=lx-1;    for(int i=lx;i<=rx;i++)if(q[i].l<=mid+1&&q[i].r>=mid) nq[++tot]=q[i];    d0=tot;    for(int i=lx;i<=rx;i++)if(q[i].r<mid) nq[++tot]=q[i];    d1=tot;    for(int i=lx;i<=rx;i++)if(q[i].l>mid+1) nq[++tot]=q[i];     for(int i=lx;i<=rx;i++) q[i]=nq[i];    memset(lef[mid+1],0x3f,sizeof(lef[mid+1]));    for(int i=1;i<=n;i++) lef[mid+1][i][i]=0;    for(int t=mid;t>=L;t--)     {        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                lef[t][i][j]=lef[t+1][i][j]+e[t].r;        for(int i=1;i<=n;i++)        {            chkmin(lef[t][e[t].x][i],lef[t+1][e[t].y][i]+e[t].c);               chkmin(lef[t][e[t].y][i],lef[t+1][e[t].x][i]+e[t].c);           }       }    memset(rig[mid],0x3f,sizeof(rig[mid]));    for(int i=1;i<=n;i++) rig[mid][i][i]=0;    for(int t=mid+1;t<=R;t++)     {        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                rig[t][i][j]=rig[t-1][i][j]+e[t].r;        for(int i=1;i<=n;i++)        {            chkmin(rig[t][i][e[t].x],rig[t-1][i][e[t].y]+e[t].c);               chkmin(rig[t][i][e[t].y],rig[t-1][i][e[t].x]+e[t].c);           }    }    for(int i=lx;i<=d0;i++)        for(int j=1;j<=n;j++)            chkmin(q[i].ans,lef[q[i].l][q[i].s][j]+rig[q[i].r][j][q[i].t]);    solve(L,mid,d0+1,d1);    solve(mid+1,R,d1+1,rx);     }int main(){    n=read();m=read();numq=read();    for(int i=1;i<=m;i++)        e[i].x=read(),e[i].y=read(),e[i].c=read(),e[i].r=read();    for(int i=1;i<=numq;i++)        q[i].s=read(),q[i].t=read(),q[i].l=read(),q[i].r=read(),q[i].id=i,q[i].ans=1e10;    solve(1,m,1,numq);    sort(q+1,q+numq+1,cmp);    for(int i=1;i<=numq;i++)        if(q[i].ans>2e9) puts("-1");        else printf("%lld\n",q[i].ans);    return 0;}
原创粉丝点击