JZOJ5959【NOIP2018模擬11.8A組】鐵路運輸
阿新 • • 發佈:2019-01-12
Description
Input
Output
Data Constraint
題意:給出一個邊權為1的無向圖,q次操作,將一條邊的邊權變為2,每次操作後詢問有多少個點的通往1的最短路比所有操作前的最短路小。
無向圖上的邊權修改問題不好做,我們可以考慮將其轉換為最短路圖。假設我們構建出了一個最短路圖,如果我們將這個圖中的邊變為2,有一個顯然的結論這條邊一定不能再走了,實際上就是一個刪邊的操作。進一步地思考,如果有一個時刻一個點可以通往1,那麼最短路不變,反之最短路就改變了,所以我們實際上要求出的是每一個點在什麼時刻與1斷開。
對於最短路圖,這是一個有向無環圖,考慮DP,設f[i]表示i節點斷開的時間,將每一條邊賦為其斷開的時間,那麼i節點斷開的時間就是它通往1號節點的所有路徑上的最小時間的最大值。
我們從1號節點往下轉移即可。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define maxn 100010 #define maxm 400020 #define maxd 200020 using namespace std; int n,m,q,i,j,k,x,y; int em,e[maxm],ec[maxm],nx[maxm],ls[maxn],num[maxm][2]; int dis[maxn],d[maxd],vis[maxn],ans[maxm]; int Em,E[maxm],Ec[maxm],Nx[maxm],Ls[maxn],f[maxn]; void spfa(){ int t=0,w=1,i,j,x,y; for(i=1;i<=n;i++) dis[i]=1e9,vis[i]=0; vis[1]=1,dis[1]=0;f[1]=q+1; d[1]=1; while (t<w){ t=(t+1)%maxd,x=d[t]; vis[x]=0; for(i=ls[x];i;i=nx[i]) if (dis[x]+1<dis[e[i]]){ dis[e[i]]=dis[x]+1; if (!vis[e[i]]){ vis[e[i]]=1; w=(w+1)%maxd,d[w]=e[i]; } } } } void bfs(){ int t=0,w=1,i,j,x,y; for(i=1;i<=n;i++) vis[i]=0; d[1]=1; vis[1]=1; while (t<w){ x=d[++t],vis[x]=1; for(i=Ls[x];i;i=Nx[i]) { y=E[i]; f[y]=max(f[y],min(f[x],Ec[i])); if (!vis[y]) d[++w]=y,vis[y]=1; } } } int main(){ freopen("train.in","r",stdin); freopen("train.out","w",stdout); scanf("%d%d%d",&n,&m,&q); for(i=1;i<=m;i++){ scanf("%d%d",&x,&y); em++; e[em]=y; nx[em]=ls[x]; ls[x]=em; num[i][0]=em; ec[em]=q+1; em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; num[i][1]=em; ec[em]=q+1; } for(i=1;i<=q;i++){ scanf("%d",&k); ec[num[k][0]]=ec[num[k][1]]=i; } spfa(); for(x=1;x<=n;x++){ for(i=ls[x];i;i=nx[i]) if (dis[x]+1==dis[e[i]]) Em++,E[Em]=e[i],Nx[Em]=Ls[x],Ls[x]=Em,Ec[Em]=ec[i]; } bfs(); for(i=1;i<=n;i++) ans[f[i]]++; for(i=1;i<=q;i++) ans[i]=ans[i-1]+ans[i]; for(i=1;i<=q;i++) printf("%d\n",ans[i]); }