2018.06.29 NOIP模拟 边的处理(分治+dp)
边的处理(side.cpp)
【问题描述】
有一个 n 个点的无向图,给出 m 条边,每条边的信息形如<x,y,c,r><x,y,c,r><x,y,c,r>。
给出 q 组询问形如<u,v,l,r><u,v,l,r><u,v,l,r>。接下来解释询问以及边的意义。询问表示,一开始你在点 u 上,然后按顺序处理编号从 l 到 r 的边。
对于一条边<x,y,c,r><x,y,c,r><x,y,c,r>,你可以进行两种操作:
1、如果你当前在 x 点或者 y 点上,那么你可以走这条边(从 x 到 y 或从 y 到 x)并付
出 c 的代价(当然你也可以不走,看操作 2)。
2、如果你不走这条边或者不可以走这条边(即你当前不在 x 或 y 上),那么你需要付出
r 的代价。
询问如果要从 u 点开始,按顺序处理完编号从 l 到 r 的边之后到达 v 点的最小代价,如
果不能到达 v,那么输出-1。
边和点的编号从 1 开始。
【输入格式】
第一行三个数表示 n,m,q。
接下来 m 行,每行四个整数 x,y,c,r 描述一条边。
接下来 q 行,每行四个整数 u,v,l,r 描述一组询问。
【输出格式】
输出共 q 行,每行一个数表示对应询问的答案。
【样例输入 1】
5 5 3
1 4 4 5
4 1 6 1
2 1 2 9
2 5 1 0
1 5 2 5
2 2 2 4
5 4 5 5
1 5 2 5
【样例输出 1】
10
-1
9
【样例输入 2】
4 8 6
2 4 5 8
2 4 4 8
2 3 6 4
1 4 5 0
2 4 10 10
1 3 5 2
3 2 2 9
3 4 1 1
3 2 1 5
3 1 2 2
1 1 1 7
2 3 2 4
3 3 1 7
1 2 2 5
【样例输出 2】
32
-1
41
14
36
27
【数据规模与约定】
对于 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。
对于 100%的数据:c,r 的取值范围是[0,10000]。
考试的时候读完题就感觉凉了,本蒟蒻和ykykyk神仙一起尝试暴力骗202020分,ykykyk的dpdpdp轻松过掉前444个点,然而我连样例都没跑过,真是丢脸。
相信大家读完题后大家都能判断这是一道玄学dpdpdp,但再一看数据范围,大家估计都想大骂出题人毒瘤了。言归正传,这题怎么做呢?准确的说,这题如何优化dpdpdp呢?
好吧我们需要上一波分治,我们假设当前正在处理边的范围在(l,r)(l,r)(l,r)之间的询问,区间的中点为midmidmid那么对于每个询问,它的左右端点有三种情况
- 第一种情况:询问的右端点在midmidmid的左边。
- 第二种情况:询问的区间恰好包含了midmidmid。
- 第三种情况:询问的左端点在midmidmid的右边。
对于情况一和情况三,显然我们可以递归处理,对于情况二,就要用到我们的dpdpdp了,由于题目上要求我们需要按序处理每条边。所以我们可以用DPDPDP得到lf[i][x][y]lf[i][x][y]lf[i][x][y]表示从xxx出发,处理了从iii到midmidmid的边之后到达yyy的最小代价,以及rf[i][x][y]rf[i][x][y]rf[i][x][y]表示从xxx出发,处理了从 mid+1mid+1mid+1到iii的边之后到达yyy的最小代价,查询的时候只要枚举一下中间断点kkk,然后执行状态转移方程ans[q[i].id]=min(ans[q[i].id],lf[q[i].l][k][q[i].u]+rf[q[i].r][k][q[i].v])ans[q[i].id]=min(ans[q[i].id],lf[q[i].l][k][q[i].u]+rf[q[i].r][k][q[i].v])ans[q[i].id]=min(ans[q[i].id],lf[q[i].l][k][q[i].u]+rf[q[i].r][k][q[i].v])就行了 。
怎么求lflflf和rfrfrf呢?我们可以对于每一个点先假设它不走新的边,那么lf[i][u][v]=lf[i+1][u][v]+e[i].r;lf[i][u][v]=lf[i+1][u][v]+e[i].r;lf[i][u][v]=lf[i+1][u][v]+e[i].r;并且rf[i][u][v]=rf[i−1][u][v]+e[i].r;rf[i][u][v]=rf[i-1][u][v]+e[i].r;rf[i][u][v]=rf[i−1][u][v]+e[i].r;,如果这个点可以走新的边,那么我们用这条边连接的另外一个点的lflflf和rfrfrf的值来更新当前点的,也就是lf[i][u][e[i].y]=min(lf[i][u][e[i].y],lf[i+1][u][e[i].x]+e[i].c);lf[i][u][e[i].x]=min(lf[i][u][e[i].x],lf[i+1][u][e[i].y]+e[i].c);lf[i][u][e[i].y]=min(lf[i][u][e[i].y],lf[i+1][u][e[i].x]+e[i].c);lf[i][u][e[i].x]=min(lf[i][u][e[i].x],lf[i+1][u][e[i].y]+e[i].c);lf[i][u][e[i].y]=min(lf[i][u][e[i].y],lf[i+1][u][e[i].x]+e[i].c);lf[i][u][e[i].x]=min(lf[i][u][e[i].x],lf[i+1][u][e[i].y]+e[i].c);和rf[i][u][e[i].y]=min(rf[i][u][e[i].y],rf[i−1][u][e[i].x]+e[i].c);rf[i][u][e[i].x]=min(rf[i][u][e[i].x],rf[i−1][u][e[i].y]+e[i].c);rf[i][u][e[i].y]=min(rf[i][u][e[i].y],rf[i-1][u][e[i].x]+e[i].c);rf[i][u][e[i].x]=min(rf[i][u][e[i].x],rf[i-1][u][e[i].y]+e[i].c);rf[i][u][e[i].y]=min(rf[i][u][e[i].y],rf[i−1][u][e[i].x]+e[i].c);rf[i][u][e[i].x]=min(rf[i][u][e[i].x],rf[i−1][u][e[i].y]+e[i].c);
另一方面,为了给下一层的递归做准备,我们可以类比整体二分的思想,利用辅助数组重新排列修改过的qqq的顺序,实现细节详见代码。
代码如下:
#include<bits/stdc++.h>
#define Q 200005
#define M 20005
#define N 35
#define inf 0x3f3f3f3f
using namespace std;
int n,m,t,lf[M][N][N],rf[M][N][N],ans[Q];
struct node{int x,y,r,c;}e[M];
struct Node{int u,v,l,r,id;}q[Q],tmp[Q];
inline void solve(int l,int r,int ql,int qr){
if(ql>qr)return;
if(l==r){
for(int i=ql;i<=qr;++i){
ans[q[i].id]=inf;
if((q[i].u==e[l].x&&q[i].v==e[l].y)||(q[i].u==e[l].y&&q[i].v==e[l].x))ans[q[i].id]=e[l].c;
if(q[i].u==q[i].v)ans[q[i].id]=min(ans[q[i].id],e[l].r);
}
return;
}
int mid=l+r>>1;
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)
lf[mid+1][i][j]=rf[mid][i][j]=inf;
for(int i=1;i<=n;++i)lf[mid+1][i][i]=rf[mid][i][i]=0;
for(int i=mid;i>=l;--i){
for(int u=1;u<=n;++u)for(int v=1;v<=n;++v)lf[i][u][v]=lf[i+1][u][v]+e[i].r;
for(int u=1;u<=n;++u){
lf[i][u][e[i].x]=min(lf[i][u][e[i].x],lf[i+1][u][e[i].y]+e[i].c);
lf[i][u][e[i].y]=min(lf[i][u][e[i].y],lf[i+1][u][e[i].x]+e[i].c);
}
}
for(int i=mid+1;i<=r;++i){
for(int u=1;u<=n;++u)for(int v=1;v<=n;++v)rf[i][u][v]=rf[i-1][u][v]+e[i].r;
for(int u=1;u<=n;++u){
rf[i][u][e[i].x]=min(rf[i][u][e[i].x],rf[i-1][u][e[i].y]+e[i].c);
rf[i][u][e[i].y]=min(rf[i][u][e[i].y],rf[i-1][u][e[i].x]+e[i].c);
}
}
for(int i=ql;i<=qr;++i)
if(q[i].l<=mid&&mid<q[i].r)
for(int k=1;k<=n;++k)
ans[q[i].id]=min(ans[q[i].id],lf[q[i].l][k][q[i].u]+rf[q[i].r][k][q[i].v]);
int sl=ql-1,sr=qr+1;
for(int i=ql;i<=qr;++i)tmp[i]=q[i];
for(int i=ql;i<=qr;++i)if(tmp[i].r<=mid)q[++sl]=tmp[i];
for(int i=qr;i>=ql;--i)if(tmp[i].l>mid)q[--sr]=tmp[i];
solve(l,mid,ql,sl),solve(mid+1,r,sr,qr);
}
int main(){
memset(ans,inf,sizeof(ans));
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=m;++i)scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].c,&e[i].r);
for(int i=1;i<=t;++i)scanf("%d%d%d%d",&q[i].u,&q[i].v,&q[i].l,&q[i].r),q[i].id=i;
solve(1,m,1,t);
for(int i=1;i<=t;++i)cout<<((ans[i]==inf)?-1:ans[i])<<'\n';
return 0;
}
2018.06.29 NOIP模拟 边的处理(分治+dp)的更多相关文章
- 2018.06.29 NOIP模拟 Gcd(容斥原理)
Gcd 题目背景 SOURCE:NOIP2015-SHY-2 题目描述 给出n个正整数,放入数组 a 里. 问有多少组方案,使得我从 n 个数里取出一个子集,这个子集的 gcd 不为 1 ,然后我再从 ...
- 2018.06.29 NOIP模拟 Minimum(最小生成树)
Minimum 题目背景 SOURCE:NOIP2015-SHY-2 题目描述 给出一幅由 n 个点 m 条边构成的无向带权图. 其中有些点是黑点,另外点是白点. 现在每个白点都要与他距离最近的所有黑 ...
- 2018.06.29 NOIP模拟 1807(简单递推)
1807 题目背景 SOURCE:NOIP2015-SHY-2 题目描述 给出一个由数字('0'-'9')构成的字符串.我们说一个子序列是好的,如果他的每一位都是 1.8.0.7 ,并且这四个数字按照 ...
- 2018.06.29 NOIP模拟 繁星(前缀和)
繁星 [问题描述] 要过六一了,大川正在绞尽脑汁想送给小伙伴什么礼物呢.突然想起以前拍过一张夜空中的繁星的照片,这张照片已经被处理成黑白的,也就是说,每个像素只可能是两个颜色之一,白或黑.像素(x,y ...
- 2018.06.29 NOIP模拟 旅馆(线段树)
旅馆 [问题描述] OIEROIEROIER 们最近的旅游计划,是到长春净月潭,享受那里的湖光山色,以及明 媚的阳光.你作为整个旅游的策划者和负责人,选择在潭边的一家著名的旅馆住 宿.这个巨大的旅馆一 ...
- 2018.06.29 NOIP模拟 排列(线段树)
排列(premu.cpp) [题目描述] 对于一个 1 到 n 的排列,逆序数的定义为:排列中第 i 位 ai的逆序数就是 a1-ai-1中比 ai大的数的个数.另外用 pi表示 a1,-,ai的逆序 ...
- 2018.06.29 NOIP模拟 区间(前缀和差量)
区间(interval.cpp) 时限:2000ms 空间限制:512MB [问题描述] 给出一个长度为 n 的序列 a[1]-a[n]. 给出 q 组询问,每组询问形如<x,y>< ...
- 2018.08.29 NOIP模拟 movie(状压dp/随机化贪心)
[描述] 小石头喜欢看电影,选择有 N 部电影可供选择,每一部电影会在一天的不同时段播 放.他希望连续看 L 分钟的电影.因为电影院是他家开的,所以他可以在一部电影播放过程中任何时间进入或退出,当然他 ...
- 2018.06.27 NOIP模拟 节目(支配树+可持久化线段树)
题目背景 SOURCE:NOIP2015-GDZSJNZX(难) 题目描述 学校一年一度的学生艺术节开始啦!在这次的艺术节上总共有 N 个节目,并且总共也有 N 个舞台供大家表演.其中第 i 个节目的 ...
随机推荐
- leetcode122
public class Solution { public int MaxProfit(int[] prices) { var list = new List<KeyValuePair< ...
- 万字总结:学习MySQL优化原理,这一篇就够了!
前言 说起MySQL的查询优化,相信大家收藏了一堆奇技淫巧:不能使用SELECT *.不使用NULL字段.合理创建索引.为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的 ...
- JS检测当前设备是PC还是移动端
用到的时候找到的分享下,也是收藏下,本地收藏多了感觉找起来很麻烦 方法1: function IsPC() { var userAgentInfo = navigator.userAgent; var ...
- servlet和JSP页面乱码问题
JSP和Servlet的中文乱码处理 前几天学习了JSP和Servlet中有关中文乱码的一些问题,写成了博客,今天进行更新一下.应该是可以解决日常的乱码问题了.现在作以下总结希望对需要的人有所帮助.我 ...
- one by one 项目 part 1
今天安装MySQL,我的系统是win8.1,安装包是mysql-5.7.17-winx64.zip,遇到了不少问题,特在此总结,希望能帮到遇到同样情况的人. 1.前面按照网上教程,先解压,然后在cmd ...
- 吴裕雄 python神经网络 水果图片识别(2)
import osimport numpy as npimport matplotlib.pyplot as pltfrom skimage import color,data,transform,i ...
- 梯度下降法】三:学习率衰减因子(decay)的原理与Python
http://www.41443.com/HTML/Python/20161027/512492.html
- Linux查看内存使用情况
输入:top PID:进程的ID USER:进程所有 PR:进程的优先级别,越小越优先被执 NInice: VIRT:进程占用的虚拟内 RES:进程占用的物理内 SHR:进程使用的共享内 S:进程的状 ...
- Java.sql.SQLException: 无效的列类型: 1111
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: ...
- Android通过DeepLink方式跳转其他App传递参数
网上对于安卓DeepLink方式跳转传递参数的例子较少,说的也不客观,实践之后发现还是有一些坑.其实为什么要用DeepLink方式跳转,有些是因为引流的原因,他们希望通过网页就能直接跳转到App的界面 ...