1 条题解

  • 0
    @ 2026-4-30 0:42:26

    把一条边边权增大相当于删掉这条边,因为包含它的路径的长度一定不可能和原来的最短路一样。

    先 bfs 一遍找出所有点和 11 的距离,以及最短路上可能的前驱个数,删一条边的时候如果发现它指向的节点所有前驱都废掉了就把它也废掉,然后删除它的所有出边。这个点的最短路长度变大,所以经过它的最短路径长度也变大。

    每个点和每条边最多被删一次,总复杂度 O(n+m+q)O(n+m+q)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const ll N=200007;
    struct edge{ll to,nxt;}e[N<<1];
    ll n,m,k,x,ans,nE=1,hd[N],dis[N],cnt[N],ok[N<<1];
    queue<int> q;
    void add(int u,int v){e[++nE]=(edge){v,hd[u]};hd[u]=nE;}
    void del(int x){
    	int u=e[x^1].to,v=e[x].to;
    	if (ok[x]||dis[v]!=dis[u]+1) return;
    //	cout<<"del "<<u<<' '<<v<<'\n';
    //	cout<<"erase "<<v<<endl;
    	ok[x]=1;
    	if ((--cnt[v])==0){
    //		cout<<"bad "<<v<<'\n';
    		++ans;
    		for (int i=hd[v];i;i=e[i].nxt) del(i);
    	}
    }
    int main(){
    	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	memset(dis,0x3f,sizeof(dis));dis[1]=0;
    	cin>>n>>m>>k;
    	for (int u,v,i=1;i<=m;++i){
    		cin>>u>>v;
    		add(u,v);add(v,u);
    	}
    	q.push(1);
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for (int v,i=hd[u];i;i=e[i].nxt){
    			v=e[i].to;
    			if (dis[v]<=dis[u]) continue;
    			if (dis[v]==dis[u]+1) ++cnt[v];
    			else{
    				dis[v]=dis[u]+1;cnt[v]=1;q.push(v);
    			}
    		}
    	}
    	while(k--){
    		cin>>x;del(x<<1);del(x<<1|1);
    		cout<<ans<<'\n';
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    9018
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者