NOIP模拟:边的处理(分治)
来源:互联网 发布:天涯社区知乎 编辑:程序博客网 时间:2024/05/21 18:40
有一个n个点的无向图,给出m条边,每条边的信息形如
<x,y,c,r>
给出q组询问形如<u,v,l,r>
接下来解释询问以及边的意义。
询问表示,一开始你在点u上,然后按顺序处理编号从1 到r 的边。
对于一条边<x,y,c,r> ,你可以进行两次操作:
1、如果你当前在x 点或者y 点上,那么你可以走这条边(从x 到y 或从y 到x )并付出c 的代价(当然你也可以不走,看操作2 )。
2、如果你不走这条边或者不可以走这条边(即你当前不在x 或y 上),那么你需要付出r 的代价。
询问如果要从点u 开始,按顺序处理完编号从l 到r 的边之后到达点v 的最小代价,如果不能到达v ,那么输出−1
n≤30,m≤20000,q≤200000
题解:
朴素的分块做法:
将边分成若干连续块,
Code:http://paste.ubuntu.com/25879122/
分块的瓶颈:依然不能高效整合区间,只能选择折中的办法。
进一步发现许多区间重复处理了很多次,如果能将这些区间接近的询问合并到一起DP会更优,于是就有了分治的做法:
对于每个分治点中心,先处理所有在中心点左边和右边的询问,并维护值
时间复杂度
#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');}
阅读全文
0 0
- NOIP模拟:边的处理(分治)
- NOIP模拟 边的处理【分治+动态规划】
- NOIP模拟(11.03)T3 边的处理
- 【NOIP模拟考三】分治 third 火柴排队(ranks.cpp)
- 20151004的NOIP模拟赛
- 20151005的NOIP模拟赛
- 20151006的NOIP模拟赛
- 20151007的NOIP模拟赛
- 20151017的NOIP模拟赛
- 20151024的NOIP模拟赛
- 20151031的NOIP模拟赛
- 【NOIP模拟】我的天
- 【NOIP模拟】天使的分裂
- NOIP模拟 门票(dfs)
- NOIP模拟:Subset(分块)
- (洛谷 1632 点的移动 noip 模拟 tower)<脑洞题>
- NOIP模拟(10.22)T2 杆子的排列
- NOIP模拟(10.27)T2 遥远的金字塔
- hdu 2049 考新郎
- 《深入浅出struts2》--第八章,输入验证-内建验证程序required,requiredstring和stringlength
- Python高级编程——8.python是一门动态语言
- 二维RMQ--poj2019 cornfield
- HTML5 表单,新标签
- NOIP模拟:边的处理(分治)
- android事件分发(面试篇)
- java小项目之文本编辑器
- trafodion sqcheck运行慢问题定位
- java面向对象------‘’足球论之java面向对象‘’
- java的三目运算
- 安全渗透1
- Switch能否用string做参数?
- 文章标题