最近在学习LCA的Tarjan算法,用来做1330秒过了。但是做1470的时候遇到了不小的麻烦。
本题大意:给出一棵树,给出所有的LCA询问,输出所有点成为LCA点的次数(为0不输出);
分析:这道题和1330的不同之处在于
1.LCA多次询问,需要另外建立查询表统计
2.输入时候需要特殊处理
接着道题时贡献了无数的RE,原因不清楚,都是用邻接表建树写的,后来改成STl里的vector容器建树就AC了,第一次利用STl容器做题,虽然过了,但是还是没想明白从前屡试不爽的邻接表怎么就会出问题,两个代码我都列下,以后再慢慢看。
另外试了一下,不用anc数组记录公共祖先点,直接不更新并查集代表节点,用并查集代表元节点似乎更快一点,运行情况对比如下
3016K | 688MS | 1668B |
3020K | 750MS | 1796B |
vector的:
#include<stdio.h> #include<memory.h> #include<vector> using namespace std; #define N 1001 #define Clear(a) memset(a,0,sizeof(a)) vector<int> E[N],Q[N]; int n,m,root; int father[N],count[N],color[N],anc[N],d[N]; void InitData() { int u,v,i,j,k; Clear(d); Clear(count); Clear(color); for(i=1;i<=n;i++) Q[i].clear(),E[i].clear(); for(k=1;k<=n;k++){ scanf("%d",&u); while(getchar()!='('); scanf("%d",&i); while(getchar()!=')'); for(j=1;j<=i;j++){ scanf("%d",&v); d[v]++; E[u].push_back(v); } } for(root=1;root<=n;root++) if(!d[root]) break; scanf("%d",&m); for(j=1;j<=m;j++){ while(getchar()!='('); scanf("%d%d",&u,&v); if(u==v) count[u]++; else{ Q[u].push_back(v); Q[v].push_back(u); } while(getchar()!=')'); } } int find_set(int s) { for(;s!=father[s];s=father[s]); return s; } void union_set(int u,int v) { int up=find_set(u); int vp=find_set(v); if(up!=vp) father[vp]=up; } void dfs(int s) { father[s]=s; anc[s]=s; for(int i=0;i<E[s].size();i++){ dfs(E[s][i]); union_set(s,E[s][i]); anc[find_set(s)]=s; } color[s]=1; for(int i=0;i<Q[s].size();i++){ if(color[Q[s][i]]) count[anc[find_set(Q[s][i])]]++; } } void show() { for(int i=1;i<=n;i++) if(count[i]) printf("%d:%d/n",i,count[i]); } int main() { // freopen("data.txt","r",stdin); while(scanf("%d",&n)!=EOF){ InitData(); dfs(root); show(); } return 0; }
邻接表的:
#include<stdio.h> #include<memory.h> #define N 1001 #define Clear(a) memset(a,0,sizeof(a)) struct Edge { int v; Edge *link; Edge(int v0,Edge *e):v(v0),link(e){} }*E[N],*Q[N]; int n,m,root; int father[N],count[N],color[N],anc[N],d[N]; void InitData() { int u,v,i,j,k; Clear(E); Clear(Q); Clear(d); Clear(count); Clear(color); for(k=1;k<=n;k++){ scanf("%d",&u); while(getchar()!='('); scanf("%d",&i); while(getchar()!=')'); for(j=1;j<=i;j++){ scanf("%d",&v); d[v]++; E[u]=new Edge(v,E[u]); } } for(root=1;root<=n;root++) if(!d[root]) break; scanf("%d",&m); for(j=1;j<=m;j++){ while(getchar()!='('); scanf("%d%d",&u,&v); if(u==v) count[u]++; else{ Q[u]=new Edge(v,Q[u]); Q[v]=new Edge(u,Q[v]); } while(getchar()!='('); } } int find_set(int s) { for(;s!=father[s];s=father[s]); return s; } void union_set(int u,int v) { int up=find_set(u); int vp=find_set(v); if(up!=vp) father[vp]=up; } void dfs(int s) { father[s]=s; anc[s]=s; for(Edge *e=E[s];e;e=e->link){ dfs(e->v); union_set(s,e->v); anc[find_set(s)]=s; } color[s]=1; for(Edge *e=Q[s];e;e=e->link){ if(color[e->v]) count[anc[find_set(e->v)]]++; } } void show() { for(int i=1;i<=n;i++) if(count[i]) printf("%d:%d/n",i,count[i]); } int main() { // freopen("data.txt","r",stdin); while(scanf("%d",&n)!=EOF){ InitData(); dfs(root); show(); } return 0; }