Trouble of Tyrant (固定图边加长最短路 转 直线群最小值)

2023-11-06 19:50

本文主要是介绍Trouble of Tyrant (固定图边加长最短路 转 直线群最小值),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目来源

2018 ACM-ICPC 中国大学生程序设计竞赛线上赛

Tyrant has a private island on the Pacific Ocean. He has built many luxury villas on the island. He flies here every vacation to enjoy life. He will drive his sports car between his villas. Tyrant has n villas on the island and the last villa which is numbered by n is his favorite. His money is only allowed to build one airpor located at the first villa which is numbered by 1 so every time he come to the island, he will land at the villa numbered 1. What's more Tyrant build 2*n-3 roads on the island. For every villa except the first island, there is a two-way street connecting this villa and the first villa. For every villa numbered by i (i >= 3) there is a two-way street connecting this villa and the villa numbered by i - 1. Tyrant is not satisfied, he think the road is not long enough. He asks q problems, every problem has a non negative integer d. He want to know if the length of each road is increaced by d what is the shortest distance between the first villa and his favorite villa. Notice that the increment in each problem is not cumulative -- in other words it doesn't take effect on the real road after query.

Input:

The first integer indicate the number of test cases T (T <= 10).

In each test cases the first line contains two integers n and q -- the number of villas and the number of queries (3 <= n <= 100000, 1 <= q <= 100000).

The second line contains n - 1 non-negative integers -- ai describe a road with length ai connecting villa 1 and i (2 <= i <= n)

The third line contains n - 2 non-negative integers -- bi describe a road with length bi connecting villa i - 1 and i (3 <= i <= n)

The next line contains q non-negative integers -- di means Tyrant want to know what is the shortest distance between the first villa ans his favorite villa when the length of each road is increaced by di.

All integers are 32-bit signed integer.

Output:

For each test case you should output q integers in one line means the answer for each problem.

样例输入
1
3 3
1 5
2
0 2 4
样例输出
3 7 9

【题意】

一个无向图,n个点,从1至n都有一条边,从3~n每一个点都与前一个点有条边。

然后q次询问,每次输入一个d,问假如把图的每条边都增加d,那么从1->n的最短路是多少

【分析】

这是昨天宁夏网络赛的一道题,当时二分查找没处理好就是不对,今天二分查找后面加了句l--,踢掉了原来那句,奇迹般的过了。

通过画图很容易发现从1->n的路径只有两条,要么直达,要么先一步去2~n-1中的一个,再往后一步步走到n。

那么就可以算一算,对于每一个点i,1->i ->n的初始路长是多少(这是一个定值),存在数组c[]中

当询问时,对于每个点的路长为 c[i] + (n-i+1)*d ,那么就需要求出可以作为最小值得i,即某个点满足这个式子是最小值。

令斜率a=n-i+1,截距b=c[i],令自由变量x=d,就会发现这是一个一元一次直线,而把每一个点i对应的那条直线,都画出来,大概是这样:


直线群相交形成的下边沿,就只能取到最小值的地方,对于不同的d,取最小值的直线不同,即图上的点不同。

接下来就要就出这个边沿,对于不同的d,选直线就行了。方法与bzoj 1007一样,题解。

将直线按斜率大小排序,斜率相同的按b小大排序,然后开始扫描,保存下能在下方的直线及其与前一直线的交点,便于二分找到d所在的位置。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int INF=0x3f3f3f3f;
struct node {ll x,y;
}e[N];
ll a[N],b[N],c[N];struct line{//存直线ll a,b;double x1;int dex;
}l[502020],s[502020];//l存直线,s模拟栈
bool cmp(line l1,line l2)//按斜率
{if(l1.a==l2.a)return l1.b<l2.b;return l1.a>l2.a;
}
double getx(line l1,line l2)//求两直线交点的x坐标
{return 1.0*(l2.b-l1.b)/(l1.a-l2.a);
}
int main()
{int T,n,m,u,v,q,d;cin>>T;while(T--){scanf("%d%d",&n,&m);for(int i=2;i<=n;i++) scanf("%d",&a[i]);for(int i=3;i<=n;i++) scanf("%d",&b[i]);c[n]=0;for(int i=n-1;i>=2;i--) c[i]=c[i+1]+b[i+1];for(int i=2;i<=n;i++) c[i]+=a[i];for(int i=2;i<=n;i++)l[i]=line{n-i+1,c[i]}; //step, lensort(l+2,l+n+1,cmp);int top=0;//s的下标s[++top]=l[2];s[top].x1=0;s[top].dex=2;for(int i=3;i<=n;i++)//遍历直线{if(l[i].a==l[i-1].a)continue;//会被覆盖while(top>1&&getx(l[i],s[top])<getx(s[top],s[top-1]))top--;//可以覆盖上一条直线s[++top]=l[i];s[top].x1=getx(s[top],s[top-1]);s[top].dex=i;}for(int i=0;i<m;i++){scanf("%d",&d);int l=1,r=top+1,mid;while(l<r){mid=(l+r)/2;if(s[mid].x1>d)r=mid;else l=mid+1;}l--;int dex=s[l].dex;ll ans=c[dex]+1ll*(n-dex+1)*d;if(i)printf(" ");printf("%lld",ans);}printf("\n");}
}


这篇关于Trouble of Tyrant (固定图边加长最短路 转 直线群最小值)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/358707

相关文章

Python在固定文件夹批量创建固定后缀的文件(方法详解)

《Python在固定文件夹批量创建固定后缀的文件(方法详解)》文章讲述了如何使用Python批量创建后缀为.md的文件夹,生成100个,代码中需要修改的路径、前缀和后缀名,并提供了注意事项和代码示例,... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5.

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1502 MPI Maelstrom(单源最短路dijkstra)

题目真是长得头疼,好多生词,给跪。 没啥好说的,英语大水逼。 借助字典尝试翻译了一下,水逼直译求不喷 Description: BIT他们的超级计算机最近交货了。(定语秀了一堆词汇那就省略吧再见) Valentine McKee的研究顾问Jack Swigert,要她来测试一下这个系统。 Valentine告诉Swigert:“因为阿波罗是一个分布式共享内存的机器,所以它的内存访问

poj 3159 (spfa差分约束最短路) poj 1201

poj 3159: 题意: 每次给出b比a多不多于c个糖果,求n最多比1多多少个糖果。 解析: 差分约束。 这个博客讲差分约束讲的比较好: http://www.cnblogs.com/void/archive/2011/08/26/2153928.html 套个spfa。 代码: #include <iostream>#include <cstdio>#i

hdu 3790 (单源最短路dijkstra)

题意: 每条边都有长度d 和花费p,给你起点s 终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 解析: 考察对dijkstra的理解。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstrin

poj 3255 次短路(第k短路) A* + spfa 或 dijkstra

题意: 给一张无向图,求从1到n的次短路。 解析: A* + spfa 或者 dijkstra。 详解见上一题:http://blog.csdn.net/u013508213/article/details/46400189 本题,spfa中,stack超时,queue的效率最高,priority_queue次之。 代码: #include <iostream>#i

poj 2449 第k短路 A* + spfa

poj 2449: 题意: 给一张有向图,求第k短路。 解析: A* + spfa。 一下转自:http://blog.csdn.net/mbxc816/article/details/7197228 “描述一下怎样用启发式搜索来解决K短路。 首先我们知道A*的基础公式:f(x)=g(x)+h(x);对h(x)进行设计,根据定义h(x)为当前的x点到目标点t所需要的实际距

poj 3258 二分最小值最大

题意: 有一些石头排成一条线,第一个和最后一个不能去掉。 其余的共可以去掉m块,要使去掉后石头间距的最小值最大。 解析: 二分石头,最小值最大。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <c

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p