Red Black Tree ZOJ
阿新 • • 發佈:2018-12-17
比賽時思路很普通 隊友按二分寫的 無限TLE 複雜度還是太高
每個黑點的花費只和最近的紅點祖先有關 並且一次查詢中只取最大值 利用這個特點 對查詢的點按花費降序排序 記為p1>p2>...>pk 若要使最終答案小於等於pi 那選擇變紅的點必須是[1,i]這些點的lca才行 因為如果不想辦法把這些點的花費減小 答案肯定不會小於等於pi 所有掃一遍並不斷求lca即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+10; struct node { ll w; int v,next; }; node edge[2*maxn]; ll dis[maxn]; int dp[maxn][20]; int first[maxn],book[maxn],deep[maxn],red[maxn],pre[maxn]; int n,m,q,num; bool cmp(int u,int v) { return dis[u]-dis[red[u]]>dis[v]-dis[red[v]]; } void addedge(int u,int v,ll w) { edge[num].v=v; edge[num].w=w; edge[num].next=first[u]; first[u]=num++; } void dfs(int cur,int fa,int anc) { ll w; int i,v; for(i=first[cur];i!=-1;i=edge[i].next){ v=edge[i].v,w=edge[i].w; if(v!=fa){ dp[v][0]=cur; deep[v]=deep[cur]+1,dis[v]=dis[cur]+w; if(book[v]){ red[v]=v; dfs(v,cur,v); } else{ red[v]=anc; dfs(v,cur,anc); } } } } void init() { int i,j; dp[1][0]=0; deep[1]=1,dis[1]=0; red[1]=1; dfs(1,0,1); for(j=1;(1<<j)<=n;j++){ for(i=1;i<=n;i++){ dp[i][j]=dp[dp[i][j-1]][j-1]; } } } int getlca(int u,int v) { int i; if(deep[u]<deep[v]) swap(u,v); for(i=log2(n);i>=0;i--){ if(deep[dp[u][i]]>=deep[v]) u=dp[u][i]; } if(u==v) return u; for(i=log2(n);i>=0;i--){ if(dp[u][i]!=dp[v][i]) u=dp[u][i],v=dp[v][i]; } return dp[u][0]; } int main() { ll w,ans,res1,res2,preval,val; int t,i,j,k,u,v,prelca,lca; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&m,&q); memset(first,-1,sizeof(first)); memset(book,0,sizeof(book)); num=0; for(i=1;i<=m;i++){ scanf("%d",&u); book[u]=1; } for(i=1;i<=n-1;i++){ scanf("%d%d%lld",&u,&v,&w); addedge(u,v,w),addedge(v,u,w); } init(); while(q--) { scanf("%d",&k); for(i=1,j=0;i<=k;i++){ scanf("%d",&u); if(!book[u]) pre[++j]=u; } k=j; if(k<=1) printf("0\n"); else{ sort(pre+1,pre+k+1,cmp); ans=dis[pre[2]]-dis[red[pre[2]]],preval=0; prelca=pre[1]; for(i=1;i<=k;i++){ lca=getlca(prelca,pre[i]); res1=preval+dis[prelca]-dis[lca]; res2=min(dis[pre[i]]-dis[red[pre[i]]],dis[pre[i]]-dis[lca]); val=max(res1,res2); if(i+1<=k) ans=min(ans,max(val,dis[pre[i+1]]-dis[red[pre[i+1]]])); else ans=min(ans,val); prelca=lca,preval=val; } printf("%lld\n", ans); } } } return 0; }