[洛谷P2783]有機化學之神偶爾會做作弊
阿新 • • 發佈:2018-09-10
include true 感覺 pri 裏的 ans enter 如果 !=
所以,我們可以很顯然的發現(
第一次做出來黑題祭
雖然感覺難度其實並不到黑題的難度
題解:
其實這道題並沒用什麽特別的知識,只是Tarjan求雙聯通分量和LCA的結合。
所以,我們可以很顯然的發現(如此惡劣的詞匯,逃
這道題其實就是給你一個無向圖,其中一個點雙聯通分量算作一個點,詢問兩個點之間(包括這兩個點)有多少點(註意重邊不需要縮點)。註意這裏的圖是無向圖,所以我們如果用單純的Tarjan求強連通分量,就會得到WA的好成績。
因此 --->我們用Tarjan雙聯同分量進行縮點,特判一下如果是他的父親,就不執行(去除重邊的影響),然後$O(m)$重建圖,跑一邊LCA求距離就好了
這裏有坑:
1.沒有關註重邊。
2.查詢寫成原圖中的編號,應為所在聯通塊的編號。
3.數據略卡常,要用快讀進行輸入。
CODE:
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<stack> using namespace std; #define N 10010 #define M 100010 int head[N],dfn[N],low[N]; int idx,link[N],tot1,fa[N][25]; int belong[N],m,n,tot2; int depth[N],xx[M],yy[M]; bool vis[N]; stack<int> st; struct Edge{ int from,to; }e[M*2],edge[M*2]; inline int read() { int s = 0,w = 1; char ch =getchar(); while(ch <= '0' || ch > '9') {if(ch == '-') w = -1 ; ch = getchar();} while(ch >= '0' && ch <= '9') {s = s * 10 + ch - '0',ch = getchar();} return s * w; } inline void add_edge(int u,int v) { e[++tot1].from = v; e[tot1].to = head[u]; head[u] = tot1; } int cnt; void Tarjan(int u,int from) { low[u] = dfn[u] = ++idx; st.push(u); vis[u] = true; for(int i = head[u] ; i ; i = e[i].to) { int v = e[i].from; if(v == from) continue; if(dfn[v] == -1) { Tarjan(v,u); low[u] = min(low[u],low[v]); } else if(vis[v]) low[u] = min(low[u],dfn[v]); } if(dfn[u] == low[u]) { ++cnt; while(1){ int v = st.top(); st.pop(); vis[v] = 0; belong[v]=cnt; if(v == u) break; } } } inline void add_edge2(int u,int v) { edge[++tot2].from = v; edge[tot2].to = link[u]; link[u] = tot2; } void dfs(int u,int from,int deepth) { depth[u] = deepth; fa[u][0] = from; for(int i = link[u] ; i ; i = edge[i].to) { int v = edge[i].from; if(v != from) dfs(v,u,deepth+1); } } int LCA(int u,int v) { if(depth[u] < depth[v]) swap(u,v); for(int j = 0 ; j <= 22 ; j++) if((depth[u] - depth[v]) & (1<<j)) u = fa[u][j]; if(u == v) return u; for(int i = 22 ; i >= 0 ; i--) if(fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } return fa[u][0]; } int ans[28000]; int print(int n) { int cur =0; if(n == 0) { cout<<'0';return 0; } if(n < 0) { putchar('-');n=0-n; } while(n) { int p = n % 2; ans[++cur] = p; n /= 2; } for(int i = cur ; i >= 1 ; i--) printf("%d",ans[i]); cout<<endl; } int main() { n = read(); m = read(); memset(dfn,-1,sizeof(dfn) ); memset(low,-1,sizeof(low) ); for(int i = 1 ; i <= m ; i++) { int u,v; u= read(),v = read(); xx[i] = u,yy[i] = v; add_edge(u,v); add_edge(v,u); } for(int i = 1 ; i <= n ; i++) if(dfn[i] == -1) Tarjan(i,-1); for(int i = 1 ; i <= m ; i++) { if(belong[xx[i]] != belong[yy[i]]) { add_edge2(belong[xx[i]],belong[yy[i]]); add_edge2(belong[yy[i]],belong[xx[i]]); } } dfs(belong[1],belong[1],0); for(int j = 1 ; j <= 22 ; j++) for(int i = 1 ; i <= cnt ; i++) fa[i][j] = fa[fa[i][j - 1]][j - 1]; int T; T = read(); while(T--) { int u,v; scanf("%d%d",&u,&v); int num = LCA(belong[u],belong[v]); print(depth[belong[u]] + depth[belong[v]] - depth[num] - depth[num] + 1); } return 0; }
[洛谷P2783]有機化學之神偶爾會做作弊