Arab Collegiate Programming Contest 2015 A题 Christmas Tree
这道题我们发现其实就是单纯的求lca,但是唯一的问题是他有多个点的lca需要求,但是其实只需要求dfs序最大和最小的两个即可,因为dfs表示的是包含的关系。
本题可以用优先队列保存大小值也可以用set来维护
#include<iostream> #include<queue> #include<map> #include<vector> #include<cstdio> #include<algorithm> #include<stack> #include<string> #include<cstring> #include<set> #define P pair<int,int> using namespace std; typedef long long ll; const int N=1e6+10; int cnt[N]; int h[N],ne[N],e[N],fa[N][17],idx; int depth[N],num[N]; int rnum[N]; bool vis[N]; set<int> ask; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void bfs(){ memset(depth,0x3f,sizeof depth); depth[0]=0,depth[1]=1; queue<int> q; q.push(1); while(q.size()){ int t=q.front(); q.pop(); int i; for(i=h[t];i!=-1;i=ne[i]){ int j=e[i]; if(depth[j]>depth[t]+1){ depth[j]=depth[t]+1; q.push(j); fa[j][0]=t; for(int k=1;k<=16;k++){ fa[j][k]=fa[fa[j][k-1]][k-1]; } } } } } int tot=0; void dfs(int u,int root){ num[u]=++tot; rnum[tot]=u; int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==root) continue; dfs(j,u); } } int lca(int a,int b){ if(depth[a]<depth[b]) swap(a,b); int i; for(i=16;i>=0;i--){ if(depth[fa[a][i]]>=depth[b]) a=fa[a][i]; } if(a==b) return a; for(i=16;i>=0;i--){ if(fa[a][i]!=fa[b][i]){ a=fa[a][i]; b=fa[b][i]; } } return fa[a][0]; } int main(){ int t; cin>>t; while(t--){ int n; cin>>n; tot=0; ask.clear(); idx=0; int i; memset(h,-1,sizeof h); memset(num,0,sizeof num); memset(rnum,0,sizeof rnum); memset(fa,0,sizeof fa); for(i=0;i<n-1;i++){ int u,v; scanf("%d%d",&u,&v); u++; v++; add(u,v); add(v,u); } bfs(); dfs(1,-1); int m; cin>>m; for(i=0;i<m;i++){ char s[2]; scanf("%s",s); int x; scanf("%d",&x); if(s[0]=='+'){ x++; ask.insert(num[x]); int a=*ask.begin(); auto it=ask.end(); int b=*(--it); int d=lca(rnum[a],rnum[b]); printf("%d\n",--d); } else{ x++; ask.erase(num[x]); if(!ask.size()){ printf("-1\n"); continue; } int a=*ask.begin(); auto it=ask.end(); int b=*(--it); int d=lca(rnum[a],rnum[b]); printf("%d\n",--d); } } } return 0; }
没有人不辛苦,只有人不喊疼