【JZOJ5430】【NOIP2017提高A组集训10.27】图

来源:互联网 发布:淘宝上卖的龙钞真假 编辑:程序博客网 时间:2024/05/16 14:04

Description

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

Data Constraint

对于20%的数据,n<=10,m<=1000,q<=1000
对于40%的数据,n<=10,m<=10000,q<=30000
对于60%的数据,n<=20,m<=10000,q<=30000
对于80%的数据,n<=25,m<=10000,q<=200000
对于100%的数据,n<=30,m<=20000,q<=200000

Solution

分治。mid左边设l[x][y][z]表示x~mid中从y开始z结束的最短路。mid右边设r[x][y][z]表示mid+1~x中从y开始z结束的最短路。更新一次是O(N^2)的。对于跨过mid的询问直接枚举中间点更新即可。时间复杂度O(n^2mlogm+n*q)。

Code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;const int maxn=2e5+5,maxn1=2e4+5;struct code{    int x,y,z,k,id;}q[maxn],a[maxn],d[maxn];int f[maxn1][31][31],b[maxn];int n,m,qq,i,t,j,k,x,y,z;void dg(int l,int r,int x,int y){    if (x>y) return;    if (l==r){        if (a[l].x>a[l].y) swap(a[l].x,a[l].y);        for (i=x;i<=y;i++){            b[q[i].id]=1e9;            if (q[i].x>q[i].y) swap(q[i].x,q[i].y);            if (q[i].x==a[l].x && q[i].y==a[l].y) b[q[i].id]=a[l].z;            if (q[i].x==q[i].y) b[q[i].id]=min(b[q[i].id],a[l].k);        }        return;    }    int mid=(l+r)/2,mi,mx;    memset(f[mid],127,sizeof(f[mid]));    f[mid][a[mid].y][a[mid].x]=f[mid][a[mid].x][a[mid].y]=a[mid].z;    for (i=1;i<=n;i++) f[mid][i][i]=min(a[mid].k,f[mid][i][i]);    for (i=mid-1;i>=l;i--){        for (j=1;j<=n;j++)            for (k=1;k<=n;k++)                f[i][j][k]=f[i+1][j][k]+a[i].k;        for (j=1;j<=n;j++)f[i][a[i].y][j]=min(f[i][a[i].y][j],f[i+1][a[i].x][j]+a[i].z);        for (j=1;j<=n;j++)f[i][a[i].x][j]=min(f[i][a[i].x][j],f[i+1][a[i].y][j]+a[i].z);    }    memset(f[mid+1],127,sizeof(f[mid]));    f[mid+1][a[mid+1].y][a[mid+1].x]=f[mid+1][a[mid+1].x][a[mid+1].y]=a[mid+1].z;    for (i=1;i<=n;i++) f[mid+1][i][i]=min(a[mid+1].k,f[mid+1][i][i]);    for (i=mid+2;i<=r;i++){        for (j=1;j<=n;j++)            for (k=1;k<=n;k++)                f[i][j][k]=f[i-1][j][k]+a[i].k;        for (j=1;j<=n;j++)f[i][j][a[i].y]=min(f[i][j][a[i].y],f[i-1][j][a[i].x]+a[i].z);        for (j=1;j<=n;j++)f[i][j][a[i].x]=min(f[i][j][a[i].x],f[i-1][j][a[i].y]+a[i].z);    }    mi=x-1;mx=y+1;    for (i=x;i<=y;i++)        if (q[i].z<=mid && q[i].k>mid){            b[q[i].id]=1e9;            for (j=1;j<=n;j++)                if (f[q[i].z][q[i].x][j]<1e9 && f[q[i].k][j][q[i].y]<1e9)b[q[i].id]=min(b[q[i].id],f[q[i].z][q[i].x][j]+f[q[i].k][j][q[i].y]);        }else if (q[i].k<=mid) d[++mi]=q[i];        else d[--mx]=q[i];    for (i=x;i<=mi;i++)q[i]=d[i];for (i=mx;i<=y;i++) q[i]=d[i];    dg(l,mid,x,mi);dg(mid+1,r,mx,y);}int main(){    freopen("graph.in","r",stdin);freopen("graph.out","w",stdout);    scanf("%d%d%d",&n,&m,&qq);memset(b,255,sizeof(b));    for (i=1;i<=m;i++)scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].k);    for (i=1;i<=qq;i++)scanf("%d%d%d%d",&q[i].x,&q[i].y,&q[i].z,&q[i].k),q[i].id=i;    dg(1,m,1,qq);    for (i=1;i<=qq;i++)        if (b[i]!=1e9&&b[i]>=0)printf("%d\n",b[i]);        else printf("-1\n");}
原创粉丝点击