洛谷 P1710 地铁涨价

题目背景

本题开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

 

 

    其实还是蛮好做的啊(但感觉我比正解多个Log 啊 2333),一个车站x到1的最短路都增加当且仅当对于所有dis[u]+1==dis[x]且存在边(u,x)的u,u车站到1的最短路已经增加了或者(u,x)涨价了。

    然后我们就可以先预处理一遍dis[],再把最短路的依赖关系这个DAG建出来。现在我们要做的就相当于是一个动态拓扑排序。

    一个点u能使v的度数减少1当且仅当 DAG上有 <u,v> 的边(注意这里是无向边),且( u到1的最短路增加 或者 原图中(u,v)的价格增加),并且这种效应只能产生一次。 因为后面的或 可能会使效应产生多次,所以我用map判了一下重。。。

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<map> 
#include<algorithm>
#include<cstring>
#define ll long long
const int maxn=100005;
#define pb push_back 
using namespace std;
vector<int> g[maxn];
map<int,int> ban[maxn];
int q[maxn],tp,tl,ans=0;
int id[maxn],hd[maxn],n,m,Q;
int to[maxn*4],ne[maxn*4],d[maxn];
bool v[maxn];

inline void BFS(){
	d[1]=0,v[1]=1,q[tp=tl=1]=1;
	int x;
	while(tp<=tl){
		x=q[tp++];
		for(int i=hd[x];i;i=ne[i]) if(!v[to[i]]){
			v[to[i]]=1,d[to[i]]=d[x]+1;
			q[++tl]=to[i];
		}
	}
}

inline void build(){
	for(int i=1;i<=n;i++)
	    for(int j=hd[i];j;j=ne[j]) if(d[i]+1==d[to[j]]){
	    	g[i].pb(to[j]);
	    	id[to[j]]++;
		}
}

inline void prework(){
	BFS();
	build();
}

inline void work(int x){
	int T;
	q[tp=tl=1]=x;
	while(tp<=tl){
		x=q[tp++],ans++;
		for(int i=g[x].size()-1;i>=0;i--){
			T=g[x][i];
			if(!ban[x].count(T)){
				ban[x][T]=1,id[T]--;
				if(!id[T]) q[++tl]=T;
			}
		}
	}
}

inline void solve(){
	memset(v,0,sizeof(v));
	int uu,vv,pos;
	while(Q--){
		scanf("%d",&pos),uu=to[pos],vv=to[pos+m];
		if(d[uu]>d[vv]) swap(uu,vv);
		if(d[uu]+1==d[vv])
		    if(!ban[uu].count(vv)){
		    	ban[uu][vv]=1;
		    	id[vv]--;
		    	if(!id[vv]) work(vv);
			}
		
		printf("%d\n",ans);
	}
}

int main(){
	scanf("%d%d%d",&n,&m,&Q);
	int uu,vv;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&uu,&vv);
		to[i]=vv,ne[i]=hd[uu],hd[uu]=i;
		to[i+m]=uu,ne[i+m]=hd[vv],hd[vv]=i+m;
	}
	prework();
	solve();
	return 0;
}

  

转载于:https://www.cnblogs.com/JYYHH/p/8687592.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值