JZOJ 5430 图

来源:互联网 发布:库里2017总决赛数据 编辑:程序博客网 时间:2024/06/10 22:16

Description

有一个n个点的无向图,给出m条边,每条边的信息形如(x,y,c,r
给出q组询问形如(u,v,l,r
接下来解释询问以及边的意义。
询问表示,一开始你在点u上,然后按顺序处理编号从lr的边
对于一条边(x,y,c,r),你可以进行两种操作:
1、如果你当前在x点或者y点上,那么你可以走这条边(从xy或从yx)并付出c的代价(当然你也可以不走,看第二个操作)
2、如果你不走这条边或者不可以走这条边(即你当前不在xy上),那么你需要付出r的代价。
询问如果要从u点开始,按顺序处理完编号从lr的边之后到达v点的最小代价,如果不能到达v,那么输出1
边和点的编号从1开始。

Data Constraint

n<=30,m<=2104,q<=2105

Solution

离线,考虑分治。
假设当前在处理分治边区间[L,R],设mid=(L+R)/2,处理询问区间跨过了mid的询问,可以用考虑动态规划设lef[i][x][y]表示从x出发,处理了从imid的边之后到达y的最小代价,以及rig[i][x][y]表示从x出发,处理了从mid+1i的边之后到达y的最小代价。
显然从lef[i][x][y]转移到lef[i-1][x][y]、从rig[i][x][y]转移到rig[i+1][x][y]的时间复杂度都为O(n2),因而整个分治的dp转移复杂度为O(m log m*n2)。,那么查询的时候只要枚举一下在第mid条边的中转点就好了。
总时间复杂度O(qn+q log m +m log m*n2)

Code

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,j,l) for(int i=j;i<=l;i++)#define fd(i,j,l) for(int i=j;i>=l;i--)using namespace std;typedef long long ll;const ll N=31,M=22e3,K=10*M,maxn=1e14;struct note{    int x,y,l,r;}t[M],qu[K];int ne[K],la[M],lb[K];ll dis[M][N][N],ans[K];int n,m,j,k,l,i,o,p,q;int read(){    int o=0; char ch=' ';    for(;ch<'0'||ch>'9';ch=getchar());    for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;    return o;}ll min(ll a,ll b){if(a<b)return a;else return b;}void divide(int l,int r,int op){    if(l==r){        fo(i,1,n)fo(j,1,n)dis[l][i][j]=maxn;        int x=t[l].x,y=t[l].y;        fo(j,1,n)dis[l][j][j]=t[l].r;        dis[l][x][y]=dis[l][y][x]=t[l].l;         for(int y=la[l];y;y=ne[y]){                int u=lb[y];                if(qu[u].r==l)ans[u]=dis[l][qu[u].x][qu[u].y];        }        return;    }    int mid=(l+r)/2;    divide(l,mid,0); divide(mid+1,r,1);    fo(i,1,n)fo(j,1,n)dis[mid][i][j]=maxn;    int x=t[mid].x,y=t[mid].y;    dis[mid][x][y]=dis[mid][y][x]=t[mid].l;     fo(j,1,n)dis[mid][j][j]=min(t[mid].r,dis[mid][j][j]);    fd(i,mid-1,l){        int x=t[i].x,y=t[i].y;        fo(j1,1,n)fo(j2,1,n)dis[i][j1][j2]=dis[i+1][j1][j2]+t[i].r;        fo(j,1,n)dis[i][j][x]=min(dis[i+1][j][y]+t[i].l,dis[i][j][x]);        fo(j,1,n)dis[i][j][y]=min(dis[i+1][j][x]+t[i].l,dis[i][j][y]);    }    fo(i,1,n)fo(j,1,n)dis[mid+1][i][j]=maxn;    x=t[mid+1].x,y=t[mid+1].y;    dis[mid+1][x][y]=dis[mid+1][y][x]=t[mid+1].l;     fo(j,1,n)dis[mid+1][j][j]=min(t[mid+1].r,dis[mid+1][j][j]);    fo(i,mid+2,r){        int x=t[i].x,y=t[i].y;        fo(j1,1,n)fo(j2,1,n)dis[i][j1][j2]=dis[i-1][j1][j2]+t[i].r;        fo(j,1,n)dis[i][j][x]=min(dis[i-1][j][y]+t[i].l,dis[i][j][x]);        fo(j,1,n)dis[i][j][y]=min(dis[i-1][j][x]+t[i].l,dis[i][j][y]);    }    fo(i,l,mid){    for(int y=la[i];y;y=ne[y]){            int u=lb[y];            if(qu[u].r>mid&&qu[u].r<=r){                int xx=qu[u].x,yy=qu[u].y;                int le=qu[u].l,ri=qu[u].r;                ans[u]=maxn;                fo(j,1,n)ans[u]=min(ans[u],dis[le][j][xx]+dis[ri][j][yy]);            }        }    }}int main(){    cin>>n>>m>>q;    fo(i,1,m)t[i].x=read(),t[i].y=read(),t[i].l=read(),t[i].r=read();    fo(i,1,q)qu[i].x=read(),qu[i].y=read(),    qu[i].l=read(),qu[i].r=read();    fo(i,1,q)ne[++o]=la[qu[i].l],la[qu[i].l]=o,lb[o]=i;    divide(1,m,1);    fo(i,1,q)if(ans[i]>=maxn)puts("-1");else printf("%lld\n",ans[i]);}