2018 ICPC青島網路賽 B. Red Black Tree (lca)
阿新 • • 發佈:2018-11-10
題意
給你一棵樹,有m個結點是紅色的,其中根1肯定是紅色的,其他結點的權重是到祖先的紅色結點的距離,q個詢問,每次問k個結點,在修改樹上一個點為紅色的情況下,這k個點的最大的權重的最小值,每次詢問相互獨立
題解
首先一個dfs求出每個點的權重,以及lca所需的東西,對於每個詢問,按照權重排序,把權重從大到小的合併起來,將他們的共同的lca染成紅色,也就是把這些大的用新的紅點去更新權重,然後更新答案;其中要記錄當前的lca,上一次的lca,上一次的最大的權重,用當前這個點去更新這個最大的權重,最後更新答案。
這是單純的只用lca,可以說這題非常的好了,充分利用了lca,想法很好;聽說還可以用rmq lca來做這題,感興趣可以自己看看,我也沒去看過
程式碼
#include<bits/stdc++.h> #define N 100005 #define P pair<ll,int> using namespace std; typedef long long ll; const int M=1e9+7; const int inf=1e9+7; ll d[N],b[N]; int deep[N],f[N][20],a[N],R[N]; bool ji[N],r[N]; vector<P>v[N]; void dfs(int p,int fa) { if(r[p])R[p]=p; else R[p]=R[fa]; d[p]=b[p]-b[R[p]]; deep[p]=deep[fa]+1; f[p][0]=fa; for(int i=1;i<20;i++) f[p][i]=f[f[p][i-1]][i-1]; for(int i=0;i<v[p].size();i++){ int to=v[p][i].first; if(to==fa)continue; b[to]=b[p]+v[p][i].second; dfs(to,p); } } int LCA(int x,int y) { if(deep[x]<deep[y])swap(x,y); for(int i=19;i>=0;i--) if(deep[f[x][i]]>=deep[y])x=f[x][i]; if(x==y)return x; for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } bool cmp(int x,int y){ return d[x]<d[y]; } int main() { int t,n,m,q,k; for(scanf("%d",&t);t;t--) { scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++){ d[i]=1e15; ji[i]=r[i]=0; v[i].clear(); } while(m--){ int x; scanf("%d",&x); r[x]=1; } for(int i=1;i<n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); v[x].push_back({y,z}); v[y].push_back({x,z}); } dfs(1,0); while(q--){ scanf("%d",&k); for(int i=1;i<=k;i++) scanf("%d",&a[i]); sort(a+1,a+k+1,cmp); ll ans=d[a[k-1]],mmax=0; int last=a[k]; for(int i=k-1;i;i--){ int now=LCA(last,a[i]); mmax=max(mmax+b[last]-b[now],min(b[a[i]]-b[now],d[a[i]])); ans=min(ans,max(mmax,d[a[i-1]])); last=now; } printf("%lld\n",ans); } } return 0; }