Nowcoder 練習賽 23 D Where are you 解題報告
阿新 • • 發佈:2018-12-01
Where are you
連結:
https://ac.nowcoder.com/acm/contest/272/D
來源:牛客網
題目描述
小\(p\)和他的朋友約定好去遊樂場遊玩,但是他們到了遊樂場後卻互相找不到對方了。
遊樂場可以看做是一張\(n\)個點,\(m\)條道路的圖,每條道路有邊權\(w_i\),表示第一次經過該道路時的花費(第二次及以後經過時花費為\(0\))。
現在,小\(p\)要去找他的朋友,但他的朋友行蹤很詭異,小\(p\)總是要遍歷完這\(n\)個點才能找到他,同時小\(p\)希望總花費最小。
找到朋友的方案可能不唯一,小\(p\)想知道在這所有的方案中,有多少條邊在每個方案中都會被經過。
輸入描述:
第一行兩個整數\(n\), \(m\),\(p\),分別表示點數,邊數,小\(p\)的初始位置。
接下來\(m\)行,每行兩個整數\(u\), \(v\), \(w\)表示從\(u\)到\(v有\)一條無向邊,邊權為\(w\)。
輸出描述:
輸出一個整數k,表示必須經過的邊的數量。
說明
\(2\le n < m \le 2\times 10^5,1 \le w \le 10^6\)
保證圖聯通,無自環無重邊
比賽的時候wa了一晚上,-8了...後來發現錯誤是沒有判\(set\)空然後\(*s.begin()\)在\(set\)為空的時候居然是\(0\)...
正解不是很懂,想了一個\(n\log^2n\)的辣雞做法。
思路:
先求出\(MST\),然後列舉不在\(MST\)上的邊。如果這個邊的兩點在樹上的路徑中的邊的權值小於等於這條邊,那麼樹上的那條路徑就是可以被取代的。
實現就是對兩個點及它們的\(LCA\)打樹上差分,然後\(set\)啟發式合併一下就好了。
Code:
#include <cstdio> #include <algorithm> #include <set> #include <vector> const int N=2e5+10; struct node { int u,v,w; bool friend operator <(node n1,node n2){return n1.w<n2.w;} }E[N]; int n,m,f[N],used[N],ans; int Find(int x){return f[x]=f[x]==x?x:Find(f[x]);} void Merge(int x,int y){f[Find(x)]=Find(y);} int head[N],to[N<<1],Next[N<<1],edge[N<<1],cnt; void add(int u,int v,int w) { to[++cnt]=v,Next[cnt]=head[u],edge[cnt]=w,head[u]=cnt; } void krus() { for(int i=1;i<=n;i++) f[i]=i; std::sort(E+1,E+1+m); for(int i=1;i<=m;i++) { int u=E[i].u,v=E[i].v,w=E[i].w; if(Find(u)!=Find(v)) { Merge(u,v); used[i]=1; add(u,v,w),add(v,u,w); } } } int F[N][20],dep[N]; void dfs1(int now,int fa) { for(int i=1;F[now][i-1];i++) F[now][i]=F[F[now][i-1]][i-1]; for(int i=head[now];i;i=Next[i]) { int v=to[i]; if(v!=fa) { F[v][0]=now; dep[v]=dep[now]+1; dfs1(v,now); } } } std::multiset <int > s[N]; std::vector <int > poi[N]; void dfs2(int now,int fa) { for(int i=head[now];i;i=Next[i]) { int v=to[i]; if(v==fa) continue; dfs2(v,now); if(s[v].empty()||*(s[v].begin())>edge[i]) ++ans; if(s[now].size()<s[v].size()) std::swap(s[now],s[v]); for(std::multiset<int>::iterator it=s[v].begin();it!=s[v].end();it++) s[now].insert(*it); s[v].clear(); } for(int i=0;i<poi[now].size();i++) { if(poi[now][i]<0) s[now].erase(s[now].find(-poi[now][i])); else s[now].insert(poi[now][i]); } } int LCA(int x,int y) { if(dep[x]<dep[y]) return LCA(y,x); for(int i=18;~i;i--) if(dep[F[x][i]]>=dep[y]) x=F[x][i]; if(x==y) return x; for(int i=18;~i;i--) if(F[x][i]!=F[y][i]) x=F[x][i],y=F[y][i]; return F[x][0]; } bool cmp(int n1,int n2){return n1>n2;} int main() { int p;scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=m;i++) scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w); krus(); dep[1]=1;dfs1(1,1); for(int i=1;i<=m;i++) { int u=E[i].u,v=E[i].v,w=E[i].w; if(used[i]) continue; int lca=LCA(u,v); poi[u].push_back(w); poi[v].push_back(w); poi[lca].push_back(-w); poi[lca].push_back(-w); } dfs2(1,1); printf("%d\n",ans); return 0; }
2018.12.1