Hello, Dr. John Fawcett and Dr. Luana Bulat, thank you for viewing this article. This work is about Virtual Tree, an algorithm designed to improve the time complexity of doing dynamic programming on trees.
Dr. John Fawcett said that we can set up lots of questions based on water flowing through a pipe.
Imagine that: there are
For example, there are ten houses and they are connected like this:
To prevent these aliens reaching any targets, the lowest cost is 5: we only need to cut the 1 -> 2 pipe and 1 -> 3.
It is a very basic dynamic programming on trees question and the state transition equation is not hard to think of.
Let:
According to the clarification to variables, we have got the state transition equation:
Clearly, if we do not apply any improvements to that implement, the time complexity is
A virtual tree is a simplified edition of original tree for the reason that it only saves necessary nodes.
The left hand side tree is the original tree and the right hand side is a virtual tree
In this question, because we only need to consider the targets so we can build a virtual tree includes and only includes the targets and their lowest common ancestors.
The process is below (
for i = 1 to Number of Targets:
A[i] = Target ID
Flag[Target ID] = IN
Sort array A by ID from smallest to largest
for i = 2 to The Size Of Array A:
if Flag(LCA(A(i-1),A(i))) is not IN then:
Add LCA(A(i-1),A(i)) to Array A
if Flag(ROOT) is not IN then:
Add ROOT to Array A
Now array A is the virtual tree, we can do the dynamic programming on A (because this is graph is a tree, so I prefer using edge list).
Here is the enhanced complete code (written in
xxxxxxxxxx
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while (!isdigit(c)){if (c=='-')f=-1;c=getchar();}
while (isdigit(c))x=x*10+c-48,c=getchar();
return x*f;
}
int lnk[maxn],nxt[2*maxn],son[2*maxn],w[2*maxn],p[4*maxn],top,stk[maxn],d[maxn],in[maxn],out[maxn],dfu,m[maxn],fah[maxn][maxp],q,isi[maxn],n,tot;
LL f[maxn];
void dfs(int x,int fa,int len){
in[x]=++dfu,m[x]=min(len,m[fa]);
d[x]=d[fa]+1,fah[x][0]=fa;
for (int i=lnk[x];i;i=nxt[i])if (son[i]^fa)dfs(son[i],x,w[i]);
out[x]=++dfu;
}
inline void init(){
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i<=n;i++)fah[i][j]=fah[fah[i][j-1]][j-1];
}
inline int lca(int x,int y){
if (d[x]>d[y])swap(x,y);
int delta=d[y]-d[x];
for (int k=0;(1<<k)<=delta;k++)if (delta&(1<<k))y=fah[y][k];
if (x^y){
for (int k=log2(n);k>-1;k--)if (fah[x][k]^fah[y][k])x=fah[x][k],y=fah[y][k];
return fah[x][0];
}else return y;
}
inline bool cmp(int x,int y){
int tx=x>0?in[x]:out[-x],ty=y>0?in[y]:out[-y];
return tx<ty;
}
inline void add(int x,int y,int z){
w[++tot]=z,son[tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;
}
int main(){
n=read();
for (int i=1;i<n;i++){
int x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
m[1]=m[0]=0x7fffffff,dfs(1,0,0x7fffffff),init();
q=read();
for (int t=1;t<=q;t++){
int k=read();tot=0;
for (int i=1;i<=k;i++){
int x=read();
isi[p[++tot]=x]=1,f[x]=m[x];
}
sort(p+1,p+1+tot,cmp);
for (int i=2;i<=tot;i++){
int ff=lca(p[i-1],p[i]);
if (!isi[ff])isi[p[++tot]=ff]=1;
}
int tt=tot;
for (int i=1;i<=tt;i++)p[++tot]=-p[i];
if (!isi[1])p[++tot]=1,p[++tot]=-1;
sort(p+1,p+1+tot,cmp);
for (int i=1;i<=tot;i++){
if (p[i]>0){stk[++top]=p[i];continue;}
int now=stk[top],ff=stk[--top];
if (now^1)f[ff]+=min((long long)(m[now]),f[now]);
else{printf("%lld\n",f[1]),isi[1]=0,f[1]=0;break;}
isi[now]=0,f[now]=0;
}
}
return 0;
}