JZOJ 5959. 【NOIP2018模拟11.8A组】铁路运输

题目大意

有张n个点,m条边的图,设dis[i]为1到i的最短路径。
第i次修改,将某条边的边权从1变成2。
求i次修改后,有多少个i的dis[i]变了。

题解

考虑最短路是怎么一步步求出来的。
考虑最经典的spfa。
最后能够搞出一个拓扑图。(比赛的时候一条拓扑图的边被计算很多很多次)
在拓扑图上不考虑删边,而是给边赋权。
那么一个点i的dis[i]最后什么时候改变?这个时间就是从1到i所有拓扑序列的路径权值的最大值。
定义路径权值:这条路径的边的最小权值。
直接拓扑排序即可。

危险信息

DIJ+堆优化打错了。必须找出原因。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 100010
#define M 200010
#define P(a) putchar(a)
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{
	int to,next,id;
}edge[M<<1],edge1[M<<1];
int p[M];
int head[N],tot;
int head1[N],tot1;
int dis[N],dis1[N];
int n,m,q,i,j,k,ans[M];
int qu[N*10],ql,qr,COL;
int u,v,wz,xin;
int weight[M],outd[N];
int bz[N];
bool bz1[M];
int read(){
	int fh=0,rs=0;char ch=0;
	while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
	if(ch=='-')fh=1,ch=getchar();
	while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
	return fh?-rs:rs;
}
void write(int x){
	if(x>9)write(x/10);
	P(x%10+'0');
}
void lb1(int x,int y,int z){
	edge1[++tot1].to=y;
	edge1[tot1].next=head1[x];
	edge1[tot1].id=z;
	head1[x]=tot1;
}
void lb(int x,int y,int z){
	edge[++tot].to=y;
	edge[tot].next=head[x];
	edge[tot].id=z;
	head[x]=tot;
}
void spfa0(){
	int i,x,w;
	dis[1]=0;
	fo(i,2,n)dis[i]=2139062143;
	qr=1,ql=0;
	qu[1]=1;
	while(ql<qr){
		x=qu[++ql];
		for(i=head[x];i;i=edge[i].next){
			if(dis[edge[i].to]>dis[x]+1){
				dis[edge[i].to]=dis[x]+1;
				qu[++qr]=edge[i].to;
			}
		}
	}
}
void sou(){
	int i,x;
	fo(x,1,n){
		for(i=head[x];i;i=edge[i].next)
		    if(dis[edge[i].to]==dis[x]+1){
		    	bz1[edge[i].id]=1;
		    	lb1(x,edge[i].to,edge[i].id);
		    	outd[edge[i].to]++;
			}
	}
}
void dye(){
	int i,x;
	qu[qr=1]=1;ql=0;
	bz[1]=COL;
	xin=1;
	while(ql<qr){
		x=qu[++ql];
		for(i=head1[x];i;i=edge1[i].next)
		    if(bz1[edge1[i].id]&&(bz[edge1[i].to]^COL)){
		    	qu[++qr]=edge1[i].to;
		    	bz[edge1[i].to]=COL;
		    	xin++;
			}
	}
}
int main(){
	n=read();m=read();q=read();
	fo(i,1,m){
		u=read(),v=read();
		lb(u,v,i);lb(v,u,i);
		weight[i]=2139062143;
	}
	fo(i,1,q)p[i]=read();
	spfa0();
	fo(i,1,n)bz[i]=0;
	sou();
	fo(i,1,q)weight[p[i]]=i;
	qu[qr=1]=1,ql=0;
	dis1[1]=q+1;
	while(ql<qr){
		u=qu[++ql];
		for(i=head1[u];i;i=edge1[i].next){
			outd[edge1[i].to]--;
			dis1[edge1[i].to]=Max(dis1[edge1[i].to],Min(dis1[u],weight[edge1[i].id])); 
			if(!outd[edge1[i].to]){
				qu[++qr]=edge1[i].to;
			}
		}
	}
	sort(dis1+1,dis1+n+1);
	fo(i,1,n){
		ans[dis1[i]]=ans[dis1[i-1]]+1;
	}
	fo(i,1,q)ans[i]=Max(ans[i],ans[i-1]);
	fo(i,1,q)write(ans[i]),P('\n');
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值