【codeforces gym】Increasing Costs
阿新 • • 發佈:2018-11-20
有一個 friend push_back line push pri ems tor [1] 的最短路,然後對於原圖中的一條邊權為\(w\)的邊\((i,j)\),如果說\(dis[j]=dis[i]+w\)的話,就在新圖中連\((i,num)\)和\((num,j)\)的有向邊,其中\(num\)表示的是這條邊對應的節點
,那麽處理到一個節點的時候,新圖中所有能走到當前節點的點的\(fa\)都已經處理好了,然後我們將當前節點的\(fa\)設為所有能走到這個節點的那些點的\(lca\)
Portal --> Increasing Costs
Description
給你一個\(n\)個點無重邊無自環的無向連通圖,每條邊有一個邊權,對於每一條邊,詢問去掉這條邊之後有多少個點到\(1\)號點的最短路會發生改變
Solution
會用到一個叫做滅絕樹的東西(這個名字好霸氣qwq)
? 其實不算是什麽特別高大上的玩意:滅絕樹其實就是一個點滅絕後它的子樹內的所有點都滅絕
? 然後所謂的“滅絕”其實可以理解為。。滿足什麽條件之類的,在不同的題目中有所不同(比如說在這題裏面就是。。走不到)
?
然後這道題的話,因為是刪邊,我們可以將邊也看成一個點
首先求出到\(1\)
註意到如果說我們將一條邊刪掉,也就是相當於將這條邊對應的節點\(num\)刪掉,由於這條邊刪掉了,由這條邊得到的最短路也就不能走了,對應到新圖中就是\(num\)這個節點不能走到,接著那些的只能由它走到的後繼也就不能走到了,以此類推
所以我們考慮用這樣的方式建一棵樹:我們將新圖所有的邊反過來建,然後對整個反過來的新圖拓撲排序,從後往前處理每一個節點在樹上面的\(fa\)
? 這樣建完之後會發現,刪掉一條邊對應的點\(num\)之後不能走到的點其實就是其整個子樹中的點
所以我們只要建出樹之後計算一下每個節點的子樹大小就好了
? 代碼大概長這個樣子
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define ll long long using namespace std; const int N=4e5+10,TOP=20; const ll inf=1LL<<60; struct xxx{ int y,nxt,id,dis; }a[N*2]; struct Data{ int node; ll dis; Data(){} Data(int node1,ll dis1){node=node1; dis=dis1;} friend bool operator < (Data x,Data y){return x.dis>y.dis;} }; priority_queue<Data> q; queue<int> q1; vector<int> pre[N]; int lis[N]; int h[N],f[N][TOP+1],dep[N]; ll dis[N]; int vis[N],d[N],sz[N]; int n,m,tot,S; void add(int x,int y,int dis,int id){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot; a[tot].id=id; a[tot].dis=dis;} void print(vector<int> x){ for (int i=0;i<x.size();++i) printf("%d ",x[i]); printf("\n"); } void dij(){ int u,v; while (!q.empty()) q.pop(); for (int i=1;i<=n;++i) dis[i]=inf,vis[i]=false; dis[S]=0; q.push(Data(S,dis[S])); while (!q.empty()){ v=q.top().node; q.pop(); if (vis[v]) continue; vis[v]=1; for (int i=h[v];i!=-1;i=a[i].nxt){ u=a[i].y; if (vis[u]) continue; if (dis[u]>dis[v]+a[i].dis){ dis[u]=dis[v]+a[i].dis; q.push(Data(u,dis[u])); } } } for (int x=1;x<=n;++x){ for (int i=h[x];i!=-1;i=a[i].nxt){ u=a[i].y; if (dis[u]==dis[x]+a[i].dis){ pre[u].push_back(a[i].id+n); pre[a[i].id+n].push_back(x); ++d[a[i].id+n]; ++d[x]; } } } } int get_lca(int x,int y){ if (!x||!y) return x+y; if (dep[x]<dep[y]) swap(x,y); for (int i=TOP;i>=0;--i) if (dep[f[x][i]]>=dep[y]) x=f[x][i]; if (x==y) return x; for (int i=TOP;i>=0;--i) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } void topo(int n){ int u,v; while (!q1.empty()) q1.pop(); for (int i=1;i<=n;++i) if (d[i]==0) q1.push(i); lis[0]=0; while (!q1.empty()){ v=q1.front(); q1.pop(); lis[++lis[0]]=v; for (int i=0;i<pre[v].size();++i){ u=pre[v][i]; --d[u]; if (!d[u]) q1.push(u); } } } void get_fa(int x){ int lca,Sz=pre[x].size(); if (Sz==0){ f[x][0]=0; } else if (Sz==1) f[x][0]=pre[x][0]; else if (Sz>=2){ lca=get_lca(pre[x][0],pre[x][1]); for (int i=2;i<Sz;++i) lca=get_lca(lca,pre[x][i]); f[x][0]=lca; } for (int i=1;i<=TOP;++i) f[x][i]=f[f[x][i-1]][i-1]; dep[x]=dep[f[x][0]]+1; sz[x]=(x<=n); } void solve(){ topo(n+m); for (int i=lis[0];i>=1;--i) get_fa(lis[i]); for (int i=1;i<=lis[0];++i) sz[f[lis[i]][0]]+=sz[lis[i]]; } int main(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif int x,y,z; scanf("%d%d",&n,&m); memset(h,-1,sizeof(h)); tot=0; for (int i=1;i<=m;++i){ scanf("%d%d%d",&x,&y,&z); add(x,y,z,i); add(y,x,z,i); } S=1; dij(); solve(); //for (int i=1;i<=n+m;++i) printf("%d " ,f[i][0]); printf("\n"); for (int i=1;i<=m;++i) printf("%d\n",sz[i+n]); }
【codeforces gym】Increasing Costs