洛谷 P2783 有機化學之神偶爾會做作弊 解題報告
阿新 • • 發佈:2018-06-09
ext 沒有 ron push_back line str mem 成了 info
P2783 有機化學之神偶爾會做作弊
題目背景
XS中學化學競賽組教練是一個酷愛爐石的人。
有一天他一邊搓爐石一邊監考,而你作為一個信息競賽的大神也來湊熱鬧。
然而你的化競基友卻向你求助了。
“第1354題怎麽做”<--手語 他問道。
題目描述
你翻到那一題:給定一個烴,只含有單鍵(給初中生的一個理解性解釋:就是一堆碳用橫線連起來,橫線都是單條的)。
然後炎魔之王拉格納羅斯用他的火焰凈化了一切環(???)。所有的環狀碳都變成了一個碳。如圖所示。
然後指定多組碳,求出它們之間總共有多少碳。如圖所示(和上圖沒有關系)。
但是因為在考試,所以你只能把這個答案用手語告訴你的基友。你決定用二進制來表示最後的答案。如圖所示(不要在意,和題目沒有什麽沒關系)。
輸入輸出格式
輸入格式:
第一行兩個整數\(n,m\).表示有\(n\)個點,\(m\)根鍵
接下來\(m\)行每行兩個整數\(u\),\(v\)表示\(u\)號碳和\(v\)號碳有一根鍵
接下來一個整數\(tot\)表示詢問次數
接下來\(tot\)行每行兩個整數,\(a,b\)表示詢問的兩個碳的編號
輸出格式:
共\(tot\)行
每行一個二進制數
說明
1<n<=10000,1<m<=50000
(兩個碳不成環)
人生中第一道A掉的黑題!2018.6.9
其實這題思想上不難,簡化一下問題即是:對於一個無向圖,先把環給縮點縮掉,然後求\(LCA\)即可。
無向圖縮點
LCA
code:
#include <cstdio> #include <vector> #include <cstring> using namespace std; const int N=10010; const int M=50010; struct Edge { int to,next; }edge[M<<1],edge1[M<<1]; vector <int > g[N]; int head[N],cnt=0,n,m,head1[N],cnt1=0; void add(int u,int v) { edge[++cnt].next=head[u];edge[cnt].to=v;head[u]=cnt; } void add1(int u,int v) { edge1[++cnt1].next=head1[u];edge1[cnt1].to=v;head1[u]=cnt1; } int time=0,dfn[N],low[N],used[N],ha[N],f[N],s[N],ans[N],dis[N],tot=0,n0=0; void push(int x){s[++tot]=x;} void pop(){tot--;} void tarjan(int now,int fa) { dfn[now]=low[now]=++time; push(now); used[now]=1; for(int i=head[now];i;i=edge[i].next) { int v=edge[i].to; if(v!=fa) { if(!dfn[v]) { tarjan(v,now); low[now]=min(low[now],low[v]); } else if(used[v]) low[now]=min(low[now],dfn[v]); } } if(low[now]==dfn[now]) { n0++; int k; do { k=s[tot]; ha[k]=n0; used[k]=0; pop(); }while(k!=now); } } int find(int x) { return f[x]=f[x]==x?x:find(f[x]); } void merge(int x,int y) { f[find(y)]=find(x); } void LCA(int now)//求解lca { used[now]=1; for(int i=0;i<g[now].size();i++) { int v=g[now][i]; if(!used[v]) { LCA(v); merge(now,v); } } for(int i=head1[now];i;i=edge1[i].next) { int v=edge1[i].to; if(used[v]) { int anc=find(v); ans[i+1>>1]=dis[v]+dis[now]-(dis[anc]<<1)+1; } } } void out(int x) { int len=0,tt[20]; while(x) { tt[++len]=x&1; x>>=1; } for(int i=len;i;i--) printf("%d",tt[i]); printf("\n"); } void dfs0(int now,int dep) { used[now]=1; dis[now]=dep; for(int i=0;i<g[now].size();i++) { int v=g[now][i]; if(!used[v]) dfs0(v,dep+1); } } void init() { for(int i=1;i<=n0;i++) f[i]=i; for(int i=1;i<=n0;i++) if(!used[i]) dfs0(i,1); } int main() { scanf("%d%d",&n,&m); int u,v,q; for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); add(u,v),add(v,u); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,0); for(int i=1;i<=n;i++) for(int j=head[i];j;j=edge[j].next) { int v=edge[j].to; if(ha[v]!=ha[i]) g[ha[i]].push_back(ha[v]); } scanf("%d",&q); for(int i=1;i<=q;i++) { scanf("%d%d",&u,&v); add1(ha[u],ha[v]); add1(ha[v],ha[u]); } init(); memset(used,0,sizeof(used)); for(int i=1;i<=n0;i++) if(!used[i]) LCA(i); for(int i=1;i<=q;i++) out(ans[i]); return 0; }
2018.6.9
洛谷 P2783 有機化學之神偶爾會做作弊 解題報告