NOIP模拟:边的处理(分治)

来源:互联网 发布:天涯社区知乎 编辑:程序博客网 时间:2024/05/21 18:40

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

题解:
朴素的分块做法:
将边分成若干连续块, f[i][k][j]表示i经过第k块中的所有边到达j的最小代价,每次询问暴力DP,复杂度O(n2mq),可以卡过60分。
Code:http://paste.ubuntu.com/25879122/

分块的瓶颈:依然不能高效整合区间,只能选择折中的办法。

进一步发现许多区间重复处理了很多次,如果能将这些区间接近的询问合并到一起DP会更优,于是就有了分治的做法:

对于每个分治点中心,先处理所有在中心点左边和右边的询问,并维护值f[i][j][l]表示从ij经过lmid的边的最小代价,同样维护处右边到终点的代价,再处理中间的询问即可。

时间复杂度O(mlogmn2+nq)

#include<bits/stdc++.h>typedef long long ll;using namespace std;inline int read(){    char ch=getchar();int i=0,f=1;    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}    return i*f;}inline void W(int x){    static int buf[50];    if(!x){putchar('0');return;}    if(x<0){putchar('-');x=-x;}    while(x){buf[++buf[0]]=x%10;x/=10;}    while(buf[0]){putchar(buf[buf[0]--]+'0');}    return;}const int Maxn=35,Maxm=2e4+50,Maxq=2e5+50,INF=0x7fffffff;int n,m,q;ll TM[Maxm][Maxn][Maxn],MT[Maxm][Maxn][Maxn],ans[Maxq];struct E{int x,y,c,r;}edge[Maxm];struct Q{int u,v,l,r,id;};vector<Q>qry_pos[Maxm<<2];inline void solve(int k,int l,int r){    if(l>r)return;    int mid=(l+r)>>1;    if(l!=r){        solve(k<<1,l,mid-1);        solve(k<<1|1,mid+1,r);    }    for(int e=qry_pos[k].size()-1;e>=0;e--){        Q qry=qry_pos[k][e];ll res=0x3f3f3f3f3f3f3f3f;        int u=qry.u,v=qry.v,l=qry.l,r=qry.r;        if(l!=mid&&r!=mid){            for(int i=1;i<=n;i++){                 res=min(res,TM[l][u][i]+edge[mid].r+MT[r][i][v]);                if(i==edge[mid].x)res=min(res,TM[l][u][i]+edge[mid].c+MT[r][edge[mid].y][v]);                if(i==edge[mid].y)res=min(res,TM[l][u][i]+edge[mid].c+MT[r][edge[mid].x][v]);            }        }else if(l!=mid){            res=TM[l][u][v]+edge[mid].r;            for(int i=1;i<=n;i++){                if(i==edge[mid].x&&v==edge[mid].y)res=min(res,TM[l][u][i]+edge[mid].c);                if(i==edge[mid].y&&v==edge[mid].x)res=min(res,TM[l][u][i]+edge[mid].c);            }        }else if(r!=mid){            res=MT[r][u][v]+edge[mid].r;            for(int i=1;i<=n;i++){                if(i==edge[mid].x&&u==edge[mid].y)res=min(res,MT[r][i][v]+edge[mid].c);                if(i==edge[mid].y&&u==edge[mid].x)res=min(res,MT[r][i][v]+edge[mid].c);            }        }else{            if(u==v)res=edge[mid].r;            if(u==edge[mid].x&&v==edge[mid].y)res=min(res,1ll*edge[mid].c);            if(u==edge[mid].y&&v==edge[mid].x)res=min(res,1ll*edge[mid].c);        }        ans[qry.id]=res;    }    if(l==r){        for(int i=1;i<=n;i++){            TM[l][i][i]=edge[l].r;MT[l][i][i]=edge[l].r;            if(i==edge[l].x){                TM[l][i][edge[l].y]=min(TM[l][i][edge[l].y],1ll*edge[l].c);                MT[l][i][edge[l].y]=min(MT[l][i][edge[l].y],1ll*edge[l].c);            }            if(i==edge[l].y){                TM[l][i][edge[l].x]=min(TM[l][i][edge[l].x],1ll*edge[l].c);                MT[l][i][edge[l].x]=min(MT[l][i][edge[l].x],1ll*edge[l].c);            }        }    }else{        if(k&1){            for(int i=l;i<=r;i++){                for(int j=1;j<=n;j++){                    for(int k=1;k<=n;k++){                        if(i==l){                            MT[i][j][k]=0x3f3f3f3f3f3f3f3f;                            if(j==k)MT[i][j][k]=edge[i].r;                            if(edge[i].x==j&&edge[i].y==k)MT[i][j][k]=min(MT[i][j][k],1ll*edge[i].c);                            if(edge[i].y==j&&edge[i].x==k)MT[i][j][k]=min(MT[i][j][k],1ll*edge[i].c);                            continue;                        }                        MT[i][j][k]=MT[i-1][j][k]+edge[i].r;                        if(edge[i].y==k)MT[i][j][k]=min(MT[i][j][k],MT[i-1][j][edge[i].x]+edge[i].c);                        if(edge[i].x==k)MT[i][j][k]=min(MT[i][j][k],MT[i-1][j][edge[i].y]+edge[i].c);                    }                }            }         }else{            for(int i=r;i>=l;i--){                for(int j=1;j<=n;j++){                    for(int k=1;k<=n;k++){                        if(i==r){                            TM[i][j][k]=0x3f3f3f3f3f3f3f3f;                            if(j==k)TM[i][j][k]=edge[i].r;                            if(edge[i].x==j&&edge[i].y==k)TM[i][j][k]=min(TM[i][j][k],1ll*edge[i].c);                            if(edge[i].y==j&&edge[i].x==k)TM[i][j][k]=min(TM[i][j][k],1ll*edge[i].c);                            continue;                        }                        TM[i][j][k]=TM[i+1][j][k]+edge[i].r;                        if(edge[i].y==j)TM[i][j][k]=min(TM[i][j][k],TM[i+1][edge[i].x][k]+edge[i].c);                        if(edge[i].x==j)TM[i][j][k]=min(TM[i][j][k],TM[i+1][edge[i].y][k]+edge[i].c);                    }                }            }        }    }}int main(){    n=read(),m=read(),q=read();    memset(TM,0x3f,sizeof(TM));    memset(MT,0x3f,sizeof(MT));    memset(ans,0x3f,sizeof(ans));    for(int i=1;i<=m;i++){        edge[i].x=read();edge[i].y=read();        edge[i].c=read();edge[i].r=read();    }    for(int i=1;i<=q;i++){        int u=read(),v=read(),l=read(),r=read();        int k=1,L=1,R=m;        while(1){            int mid=(L+R)>>1;            if(l<=mid&&mid<=r){                qry_pos[k].push_back((Q){u,v,l,r,i});                break;            }            (r<mid)?(k=k<<1,R=mid-1):(k=k<<1|1,L=mid+1);        }    }    solve(1,1,m);    for(int i=1;i<=q;i++)W((ans[i]>=INF?-1:ans[i])),putchar('\n');}
原创粉丝点击