洛谷 P1710 地铁涨价
来源:互联网 发布:c语言调用大漠插件 编辑:程序博客网 时间:2024/05/16 19:06
题目背景
本题开O2优化,请注意常数
题目描述
博艾市除了有海底高铁连接中国大陆、台湾与日本,市区里也有很成熟的轨道交通系统。我们可以认为博艾地铁系统是一个无向连通图。博艾有N个地铁站,同时有M小段地铁连接两个不同的站。
地铁计价方式很简单。从A站到B站,每经过一小段铁路(连接直接相邻的两个点的一条边),就要收取1博艾元。也就是说,从A站到B站,选择的路径不一样,要价也会不同。
我们认为凡华中学在1号地铁站。学生们通过地铁通勤,他们当然知道选择最短路来坐车的话,票价最便宜。
然而博艾地铁公司经营不善,一直亏损,于是他们打算提价。提价一次就是将一小段铁路原来收费1元改收2元。同一小段的铁路不会多次提价。他们打算提价Q次。
学生们知道,如果他们到学校的一条最短路径中的一小段提价了,可以改变路径,使总票价不变。然而随着一条一条的铁路被提价,当居住在某个站附近的学生发现,提价后,没有任何一种方案可以从家到学校的费用和初始费用相等时,就会不满。
现在地铁公司希望知道,对于每一次涨价,有多少个站,学生会因为涨价而不满呢?
输入输出格式
输入格式:
第一行为三个整数N,M,Q。
接下来M行,每行2个整数ai,bi,表示第i条铁路连接的两个站。i表示铁路编号。
接下来Q行,每行一行整数rj,表示每次涨价的铁路编号。
输出格式:
Q行。每行一个整数表示不满的车站数量。
输入输出样例
输入样例#1:
5 6 5
1 2
1 3
4 2
3 2
2 5
5 3
5
2
4
1
3
输出样例#1:
0
2
2
4
4
说明
【样例解释】
次数 车站2 车站3 车站4 车站5
初始 1 1 2 2
1 1 1 2 2
2 1 2 2 3
3 1 2 2 3
4 2 2 3 3
5 2 2 4 3
【数据范围】
对于20%的数据 N≤100, Q≤30
对于40%的数据 Q≤30
对于70%的数据 正确的输出结果中,不会有超过50种不一样的整数(数据范围剧透解法系列)
对于100%的数据 N≤100000, Q≤M≤200000
【分析】
不得不感叹这真是一道好题…
转化问题
这里路线涨价明显等同于删边,所以我们可以把问题倒过来思考:
图上依次(倒序)加边,问每个点成为最终图最短路的时间
分析
记原图的点1到达点i的最短路为dis[i],当前状态下点1到达点i最短路为d[i]。下面称d[i]==dis[i]的点i为扩展点。
通过分析最短路性质发现,某个点v新成为扩展点情况有两个
1.加边(u,v)更新,且dis[u]==d[u]&&dis[v]==d[u]+1&&d[v]!=dis[v]。
2.邻居u突然成为最终图最短路,且dis[v]==d[u]+1&&d[v]!=dis[v]
(其实上面是同一种情况XD)
重要的是,每个点只会被更新1次,体现在了上面的强调处。这是很显然的,因为这题答案是唯一确定的,但这个是降低复杂度的重要条件。
确定算法
1.首先把最终图的最短路情况dis[i]求出来。然后重建图,去掉所有待加边。
2.然后依次加入待加边,检测边的两端是否符合条件1,若符合,则进行深度优先搜索,对新成为扩展点邻居进行条件2判断。
3.将每次新成为扩展点的数目记录,最后处理出答案。
复杂度分析
1.由于边权为1,求dis[]可以用bfs遍历,复杂度为O(n+m)。
2.加入了q条边,在整个过程2中每个点只会被dfs到一次,所以复杂度为O(n+m+q)。
3.每一次的答案是新成为扩展点的数目,所以需要一遍前缀和,复杂度为O(q)。
最终复杂度为O(n+m+q)
数组开小…查了一个小时qwqqq
【代码】
//洛谷月赛 3.地铁涨价 #include<cmath>#include<queue>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long long#define M(a) memset(a,0,sizeof a)#define fo(i,j,k) for(i=j;i<=k;i++)using namespace std;const int mxn=400005;queue <int> que;int n,m,q,cnt,res;int head[mxn],dis[mxn],ans[mxn],del[2*mxn],d[mxn];struct node {int to,next;}f[mxn*4];bool vis[mxn*4],b[mxn];inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}inline void add(int u,int v){ f[++cnt].to=v; f[cnt].next=head[u]; head[u]=cnt;}inline void dfs(int u,int fa){ for(register int i=head[u];i;i=f[i].next) if(!vis[i]) { int v=f[i].to; if(v==fa) continue; if(dis[v]!=d[v] && d[v]==d[u]+1 && dis[u]==d[u]) res++,dis[v]=d[v],dfs(v,u); }}inline void spfa(bool ha){ int i,j,num=0; M(b); memset(dis,0x3f,sizeof dis); while(!que.empty()) que.pop(); dis[1]=0;b[1]=1; que.push(1); while(!que.empty()) { int u=que.front(); que.pop(); for(i=head[u];i;i=f[i].next) if(!vis[i]) { int v=f[i].to; if(!b[v]) { dis[v]=dis[u]+1; que.push(v),b[v]=1; } } } if(ha) fo(i,1,n) d[i]=dis[i]; //d储存未删边的图的状态,dis储存当前状态 }int main(){ int i,j,u,v,w; n=read(),m=read(),q=read(); fo(i,1,m) { u=read(),v=read(); add(u,v);add(v,u); } spfa(1); fo(i,1,q) { w=read(); del[i]=w; vis[2*w]=vis[2*w-1]=1; } spfa(0); for(i=q;i;i--) { res=0; w=del[i]*2; vis[w]=vis[w-1]=0; u=f[w].to,v=f[w-1].to; if(d[u]==dis[u] && d[v]==dis[u]+1 && dis[v]!=d[v]) //如果u能扩展至v res++,dis[v]=d[v],dfs(v,u); swap(u,v); if(d[u]==dis[u] && d[v]==dis[u]+1 && dis[v]!=d[v]) //如果u能扩展至v res++,dis[v]=d[v],dfs(v,u); ans[i]=res; } fo(i,1,q) ans[i]+=ans[i-1],printf("%d\n",ans[i]); return 0;}
- 洛谷 P1710 地铁涨价
- 洛谷 P1710 地铁涨价
- 洛谷 P1710 地铁涨价 (dfs+bfs)
- 【洛谷 P1710】地铁涨价(dfs+bfs)
- 洛谷1710 地铁涨价
- [luogu1710]地铁涨价(bfs)
- 地铁涨价,新出台的javase计算每月乘坐地铁消费金额
- 涨价
- 洛谷2583 地铁间谍
- 地铁
- 汽油涨价
- 原料涨价,危机?机会?
- 避孕药涨价女大学生叫苦
- 方便面涨价之谜
- 方便面涨价之谜
- Monster 又涨价了
- Monster 又涨价了
- Monster 又涨价了
- 判断“资源字符串”是否可以构成“目标字符串”
- Linux中的crontab配置常用的日期格式以及详细事例
- 小米系列手机开源代码
- servlet简述
- 2016.10.30 Bootstrap.6(js插件)
- 洛谷 P1710 地铁涨价
- AndrewNg机器学习第四周作业:关于使用逻辑回归、神经网络训练数据并应用之的心得
- java继承
- LeetCode-404. Sum of Left Leaves
- Ubuntu 设置中文语言
- 图像三大特征
- Android Studio下jni应用
- mysql一些复制表、增删改索引、建存储过程、创建函数、创建触发器的一些命令
- java封装