1. 程式人生 > >HDU 6031 Innumerable Ancestors

HDU 6031 Innumerable Ancestors

bits sin oid upd space while dfs add 更新

樹狀數組,倍增,枚舉,$dfs$序。

對於每一次的詢問,可以枚舉$B$集合中的所有點,對於每一個點,在樹上二分$LCA$,找到最低的更新答案。

判斷是否是$LCA$可以搞個$dfs$序,將$A$集合中所有點標$1$,然後查詢子樹對應的區間上的區間和。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 100010;
int L[maxn],R[maxn];
int c[2*maxn];
int h[maxn];
int to[2*maxn];
int nx[2*maxn];
int sz;
int tt; int dp[100010][25]; int dep[100010]; int ans; int n,m; int k1,k2; int A[100010],B[100010]; void add(int a,int b) { to[sz] = b; nx[sz] = h[a]; h[a] = sz++; } void dfs(int x,int y) { L[x] = tt; tt++; dp[x][0] = y; if(y==-1) dep[x]=1; else dep[x] = dep[y]+1;
for(int i=h[x];i!=-1;i = nx[i]) { if(L[to[i]]) continue; dfs(to[i],x); } R[x] = tt; tt++; } int lowbit(int x) { return x&(-x); } void update(int pos,int val) { for(int i=pos;i<=2*n;i=i+lowbit(i)) { c[i] += val; } } int
get(int pos) { int res=0; for(int i=pos;i>0;i=i-lowbit(i)) { res=res+c[i]; } return res; } void work(int x) { while(1) { int Q = dp[x][0]; if(get(R[Q])-get(L[Q]-1)) { ans = max(ans,dep[Q]); break; } for(int i=17;i>=0;i--) { int to = dp[x][i]; if(to==-1) continue; if(get(R[to])-get(L[to]-1)) continue; x=to; break; } } x = dp[x][0]; ans = max(ans,dep[x]); } int main() { while(~scanf("%d%d",&n,&m)) { sz=0; for(int i=0;i<=n;i++) { c[i]=0; h[i]=-1; L[i]=0; R[i]=0; } for(int i=1;i<=n-1;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } tt=1; dfs(1,-1); for(int j=1;j<=17;j++) { for(int i=1;i<=n;i++) { if(dp[i][j-1]==-1) dp[i][j]=-1; else dp[i][j] = dp[dp[i][j-1]][j-1]; } } for(int i=1;i<=m;i++) { scanf("%d",&k1); for(int j=1;j<=k1;j++) scanf("%d",&A[j]), update(L[A[j]],1); scanf("%d",&k2); ans=0; for(int j=1;j<=k2;j++) { scanf("%d",&B[j]); if(get(R[B[j]])-get(L[B[j]]-1)) { ans = max(ans,dep[B[j]]); continue; } work(B[j]); } printf("%d\n",ans); for(int j=1;j<=k1;j++) update(L[A[j]],-1); } } return 0; }

HDU 6031 Innumerable Ancestors