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");
}

624

被折叠的 条评论
为什么被折叠?



