[CSP-S模拟测试]:城市游戏(图论+DP)
题目传送门(内部题109)
输入格式
第一行,两个整数$n,m$。
接下来$m$行,每行三个整数$u,v,l$,描述了一条道路连接的两个路口的编号以及道路的长度。
输出格式
输出一行一个整数,为所求的答案。若小$A$不能到$n$达号点,输出$-1$。
样例
样例输入:
4 4
1 2 1
2 3 1
3 4 1
1 4 1
样例输出:
3
数据范围与提示
对于$10\%$的数据,满足$n\leqslant 200,m\leqslant 1,000$
对于$70\%$的数据,满足$n\leqslant 1,000,m\leqslant 2,000$
对于$40\%$的数据,满足$n\leqslant 3,000,m\leqslant 10,000$
对于$100\%$的数据,满足$1\leqslant n\leqslant 100,000,1\leqslant m\leqslant 200,000$,道路长度为不超过$10^9$的正整数。
题解
首先,小$B$一定是要“封掉”$1\sim n$的最短路上的一条边。
设$dp[i]$小$B$还没有用过“封路”时从$i$到$n$的最短路的长度,$d(i,j)$表示小$B$封掉$(i,j)$这条边之后小$A$从$i$到$n$的最短路的长度,$dis[i]$表示从$n$到$i$的最短路的长度。
假设现在小$A$在点$i$,且要走$(i,j)$这条边,那么$f[i]=\max(f[j]+l(i,j),d(i,j))$,这也就是一个带环的动态规划,可以利用类似$Dijkstra$的思路解决。
现在考虑如何求出$d(i,j)$。
有一个原题:$USACO$《安全路径》。
思路就是先构建出一棵以$n$为根的最短路树,那么只有$(i,j)$在这棵最短路树上$d(i,j)$才有意义。
不妨设删掉的这条边为$(u,v)$,父亲是$u$,儿子是$v$,那么在删掉这条边之后树分成了两个联通块。
那么我们需要找一条边$(a,b)$满足$a$在$v$的联通块内,而$b$在$u$的联通块内,那么这条路经的长度就是$dis[b]+l(a,b)+(dis[a]-dis[v])=(dis[b]+dis[a]+l(a,b))-dis[v]$。
对于上式,不妨设$dis[b]+dis[a]+l(a,b)=p(a,b)$,则想办法求的$p(a,b)$的最小值且满足$a$在$v$的子树中且$b$不在。
枚举$v$显然不可行,考虑枚举$(a,b)$,看它能对哪些$v$做贡献。
还可以发现$v$一定在$a\sim b$的树链上,且不能是$a$和$b$的$lca$。
暴力是不可行的,但是可以按$p(a,b)$排序,那么赋值过一次就不能再被赋值了,可以用并查集维护。
时间复杂度:$\Theta(\omega m+m\log n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
- #include<bits/stdc++.h>
- using namespace std;
- struct rec{int nxt,to,w;bool is;}e[2][400002];
- int head[2][100001],cnt[]={1,1},sz;
- int n,m;
- int pre[100001],fa[100001][21],depth[100001];
- long long dis[100001],dp[100001],ans[100001];
- bool vis[100001],is[400002];
- priority_queue<pair<long long,int>,vector<pair<long long,int>>,greater<pair<long long,int>>>q;
- bool cmp(rec a,rec b){return a.w<b.w;}
- void add(bool id,int x,int y,int w)
- {
- e[id][++cnt[id]].nxt=head[id][x];
- e[id][cnt[id]].to=y;
- e[id][cnt[id]].w=w;
- head[id][x]=cnt[id];
- }
- void Dij()
- {
- q.push(make_pair(0,n));
- while(q.size())
- {
- int x=q.top().second;q.pop();
- if(vis[x])continue;vis[x]=1;
- for(int i=head[0][x];i;i=e[0][i].nxt)
- {
- if(dis[e[0][i].to]>dis[x]+e[0][i].w)
- {
- dis[e[0][i].to]=dis[x]+e[0][i].w;
- pre[e[0][i].to]=i;
- q.push(make_pair(dis[e[0][i].to],e[0][i].to));
- }
- }
- }
- }
- void dfs(int x)
- {
- for(int i=head[1][x];i;i=e[1][i].nxt)
- {
- fa[e[1][i].to][0]=x;
- depth[e[1][i].to]=depth[x]+1;
- for(int j=1;j<=20;j++)
- fa[e[1][i].to][j]=fa[fa[e[1][i].to][j-1]][j-1];
- dfs(e[1][i].to);
- }
- }
- int LCA(int x,int y)
- {
- if(depth[x]>depth[y])swap(x,y);
- for(int i=20;i>=0;i--)
- if(depth[fa[y][i]]>=depth[x])
- y=fa[y][i];
- if(x==y)return x;
- for(int i=20;i>=0;i--)
- if(fa[x][i]!=fa[y][i])
- {
- x=fa[x][i];
- y=fa[y][i];
- }
- return fa[x][0];
- }
- void DIJ()
- {
- memset(vis,0,sizeof(vis));
- q.push(make_pair(0,n));
- while(q.size())
- {
- int x=q.top().second;q.pop();
- if(vis[x])continue;vis[x]=1;
- for(int i=head[0][x];i;i=e[0][i].nxt)
- {
- if(ans[e[0][i].to]>max(ans[x]+e[0][i].w,is[i]?dp[e[0][i].to]:dis[e[0][i].to]))
- {
- ans[e[0][i].to]=max(ans[x]+e[0][i].w,is[i]?dp[e[0][i].to]:dis[e[0][i].to]);
- q.push(make_pair(ans[e[0][i].to],e[0][i].to));
- }
- }
- }
- }
- int main()
- {
- scanf("%d%d",&n,&m);
- for(int i=1;i<n;i++)dis[i]=ans[i]=dp[i]=0x3f3f3f3f3f3f3f3f;
- for(register int i=1;i<=m;i++)
- {
- int u,v,l;
- scanf("%d%d%d",&u,&v,&l);
- add(0,u,v,l);add(0,v,u,l);
- }
- Dij();
- for(register int i=1;i<n;i++)
- {
- add(1,e[0][pre[i]^1].to,i,0);
- is[pre[i]]=is[pre[i]^1]=1;
- }
- dfs(n);
- for(register int i=2;i<=cnt[0];i+=2)
- {
- if(is[i])continue;
- int x=e[0][i].to;
- int y=e[0][i^1].to;
- int lca=LCA(x,y);
- long long val=dis[x]+dis[y]+e[0][i].w;
- while(x!=lca)
- {
- dp[x]=min(dp[x],val-dis[x]);
- x=fa[x][0];
- }
- while(y!=lca)
- {
- dp[y]=min(dp[y],val-dis[y]);
- y=fa[y][0];
- }
- }
- DIJ();
- if(ans[1]==0x3f3f3f3f3f3f3f3f)puts("-1");
- else printf("%lld",ans[1]);
- return 0;
- }
rp++
[CSP-S模拟测试]:城市游戏(图论+DP)的更多相关文章
- [CSP-S模拟测试]:抛硬币(DP)
题目背景 小$A$和小$B$是一对好朋友,他们经常一起愉快的玩耍.最近小$B$沉迷于**师手游,天天刷本,根本无心搞学习.但是小$B$已经入坑了几个月,却一次都没有抽到$SSR$,让他非常怀疑人生.勤 ...
- [CSP-S模拟测试]:B(期望DP)
题目传送门(内部题151) 输入格式 第一行一个整数$N$. 第二行$N$个整数,第$i$个为$a_i$. 输出格式 一行一个整数,表示答案.为避免精度误差,答案对$323232323$取模. 即设答 ...
- [CSP-S模拟测试]:密码(数位DP+库默尔定理)
题目描述 为了揭穿$SERN$的阴谋,$Itaru$黑进了$SERN$的网络系统.然而,想要完全控制$SERN$,还需要知道管理员密码.$Itaru$从截获的信息中发现,$SERN$的管理员密码是两个 ...
- [CSP-S模拟测试]:硬币(博弈论+DP+拓展域并查集)
题目传送门(内部题135) 输入格式 第一行包含一个整数$T$,表示数据组数. 对于每组数据,第一行两个整数$h,w$,表示棋盘大小. 接下来$h$行,每行一个长度为$w$的字符串,每个位置由为$o, ...
- [CSP-S模拟测试]:军训队列(DP+乱搞)
题目描述 有$n$名学生参加军训,军训的一大重要内容就是走队列,而一个队列的不规整程度是该队中最高的学生的身高与最矮的学生的身高差值的平方.现在要将$n$名参加军训的学生重新分成$k$个队列,每个队列 ...
- [CSP-S模拟测试]:优化(贪心+DP)
题目描述 $visit\text{_}world$发现有下优化问题可以用很平凡的技巧解决,所以他给你分享了这样一道题:现在有长度为$N$的整数序列$\{ a_i\}$,你需要从中选出$K$个不想叫的连 ...
- [CSP-S模拟测试]:玩具(概率DP)
题目描述 这个故事发生在很久以前,在$IcePrincess\text{_}1968$和$IcePrince\text{_}1968$都还在上幼儿园的时候. $IcePrince\text{_}196 ...
- [CSP-S模拟测试]:超级树(DP)
题目传送门(内部题5) 输入格式 一行两个整数$k$.$mod$,意义见上. 输出格式 一行一个整数,代表答案. 样例 样例输入1: 2 100 样例输出1: 样例输入2: 3 1000 样例输出2: ...
- [CSP-S模拟测试]:矩阵游戏(数学)
题目描述 $LZK$发明一个矩阵游戏,大家一起来玩玩吧,有一个$N$行$M$列的矩阵.第一行的数字是$1,2,...,M$,第二行的数字是$M+1,M+2,...,2\times M$,以此类推,第$ ...
随机推荐
- thinkPHP验证码报错: Call to undefined function captcha_src()
问题出现的原因可能有: 1. captcha扩展缺失: 2. captcha扩展与当前thinkPHP版本不兼容. thinkPHP6.0以下版本只能使用 captcha2.0以下版本,不支持2.0版 ...
- jinja2 模板相关
安装 pip install jinja2 配置模板 settings.py 60行左右 TEMPLATES = [ { 'BACKEND': 'django.template.backends.dj ...
- 二维数组中的查找——牛客剑指offer
题目描述: 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整 ...
- 快速幂(Fast_Power)
定义快速幂顾名思义,就是快速算某个数的多少次幂. 其时间复杂度为 O(log2N), 与朴素的O(N)相比效率有了极大的提高. 以下以求a的b次方来介绍 原理把b转换成2进制数 该2进制数第i位的权为 ...
- Nginx(高并发)
Nginx(engine x)高性能和反向代理的web服务器反向代理:保护客户资源,只要是http协议都可以Web服务器:IIS 阿帕奇 NginxNginx可以作为负载均衡(NLB只支持Http)我 ...
- iis 8.0 HTTP 错误 404.3 server 2012
最近在学习WCF,发现将网站WCF服务放到IIS上时不能正常运行,从网上搜了一下: 解决方法,以管理员身份进入命令行模式,运行: "%windir%\Microsoft.NET\Framew ...
- 部署master节点组件
部署master节点组件 master节点的组件有:kube-apiserver,kube-scheduler,kube-controller-manager 大致安装步骤如下: # mkdir -p ...
- Ngnx工作原理(1)
Nginx 是一个轻量级的HTTP 服务程序,相比其他服务器程序如Apache,Nginx占用内存少,稳定性高,并发处理能力强.同时Nginx 还是一个反向代理服务程序,和邮件代理服务程序.Nginx ...
- python 装饰器,生成器,迭代器
装饰器 作用:当我们想要增强原来已有函数的功能,但不想(无法)修改原函数,可以使用装饰器解决 使用: 先写一个装饰器,就是一个函数,该函数接受一个函数作为参数,返回一个闭包,而且闭包中执行传递进来的函 ...
- Redis总结1
一.Redis安装(Linux) 1.在官网上下载Linux版本的Redis(链接https://redis.io/download) 2.在Linux的/usr/local中创建Redis文件夹mk ...