由于今天被数据结构虐了,所以果断来水一水虚树的题。
这题每次树形DP一下大概是n*m的复杂度,妥妥的炸掉了。
然而我们只考虑每次要处理的节点和他们的LCA们,于是就变成了sigma(k),即50W了。
然后就是虚树的建法,感觉还是很有意思(不明所以)的。
首先我们需要一个单调栈来维护一条从根节点延伸下来的链,然后我们有四个节点。
1:当前点
2:栈顶
3:次栈顶
4:lca(当前点,栈顶)
考虑点4,有两种可能。
1:点4在点3的上方,那么点3向点2俩边,点2出栈。
2:点4在点2和点3的中间,那么点4向点2连边,点2出栈,点4入栈,链底部显然是点1,所以点1入栈。
于是我们就构造出了一颗虚树。
然后DP就很简单了。
然而INF开小了WA了一发。
不过由于常数写得小(树剖求lca简直nice啊),目前rank 7好开森啊。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define inf 1e60; using namespace std; const int N=250000+5; typedef long long ll; int read(){ int x=0;char ch; while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } struct Edge{int to,next,v;}e[N<<1]; int head[N],cnt; int siz[N],son[N],dep[N],fa[N],top[N]; ll d[N],mn[N]; int st[N],t,h[N],dfn[N],dfs_clock; bool cmp(int a,int b){ return dfn[a]<dfn[b]; } void ins(int u,int v,int w){ if(u==v)return; e[++cnt]=(Edge){v,head[u],w};head[u]=cnt; } void dfs1(int u){ siz[u]=1;son[u]=0; dfn[u]=++dfs_clock; for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v==fa[u])continue; dep[v]=dep[u]+1;fa[v]=u;mn[v]=min(mn[u],(ll)e[i].v); dfs1(v); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } void dfs2(int u,int tp){ top[u]=tp; if(son[u])dfs2(son[u],tp); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v!=son[u]&&v!=fa[u]) dfs2(v,v); } } int lca(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]>dep[top[v]])u=fa[top[u]]; else v=fa[top[v]]; } return dep[u]<dep[v]?u:v; } void dp(int u){ ll tmp=0; for(int i=head[u];i;i=e[i].next){ dp(e[i].to); tmp+=d[e[i].to]; } head[u]=0; if(!tmp)d[u]=mn[u]; else d[u]=min(tmp,mn[u]); } void solve(){ cnt=0; int k=read(); for(int i=1;i<=k;i++) h[i]=read(); sort(h+1,h+1+k,cmp); int tot=1; for(int i=2;i<=k;i++) if(lca(h[tot],h[i])!=h[tot])h[++tot]=h[i]; st[++t]=1; for(int i=1;i<=tot;i++){ int now=h[i],f=lca(now,st[t]); while(true){ if(dep[f]>=dep[st[t-1]]){ ins(f,st[t--],0); if(f!=st[t])st[++t]=f; break; } ins(st[t-1],st[t],0);t--; } if(st[t]!=now)st[++t]=now; } while(--t)ins(st[t],st[t+1],0); dp(1); printf("%lld\n",d[1]); } int main(){ int n=read(),u,v,w; for(int i=1;i<n;i++){ u=read();v=read();w=read(); ins(u,v,w);ins(v,u,w); } int m=read();mn[1]=inf; dfs1(1);dfs2(1,1); memset(head,0,sizeof(head)); while(m--)solve(); return 0; }