P2495 [SDOI2011] 消耗战
P2495 [SDOI2011] 消耗战
题意简述:
在一颗树上,每次给定
我们考虑dp:记
显然我们有两种切法,一种是对每个子树下的
但这样的时间复杂度是O(nq)的,显然不行
那我们该怎么办呢?
虚树闪亮登场:
虚树,顾名思义是一颗虚构的树
它只记录了关键节点,在本题中,注意到
所以我们考虑建立一颗树,上面只包含关键点和他们的lca
虚树的建立:
参考dalao题解:
Link
只要我们建立了虚树,然后直接对每个虚树结点进行树上dp然后我们这题就做完了
记得每次做完之后清空数组和之前虚树建的边!!!
Code
#include<bits/stdc++.h> #define int long long const int N=5e5+5; const int inf=1e17; const int lg=20; using namespace std; int n,m,e1_cnt,e2_cnt,dfn_cnt,top; int head1[N],head2[N],mincut[N],dfn[N],que[N],tag[N]; int dep[N],st[N]; int f[N][lg+5]; struct Edge{ int to,nxt,w; }e1[N<<1],e2[N<<1]; void add(int x,int y,int w,Edge e[],int head[],int &cnt) { e[++cnt]={y,head[x],w}; head[x]=cnt; } void dfs1(int x) { dfn[x]=++dfn_cnt; for(int i=1;i<=lg;i++) { f[x][i]=f[f[x][i-1]][i-1]; } for(int i=head1[x],to,w;i;i=e1[i].nxt) { to=e1[i].to,w=e1[i].w; if(!dfn[to]) { dep[to]=dep[x]+1; mincut[to]=min(mincut[x],w); f[to][0]=x; dfs1(to); } } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=lg;i>=0;i--) { if(dep[y]<=dep[f[x][i]])x=f[x][i]; } if(x==y)return x; for(int i=lg;~i;i--) { if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; } return f[x][0]; } int dfs2(int x) { int sum=0,res=inf; for(int i=head2[x],to;i;i=e2[i].nxt) { to=e2[i].to; sum+=dfs2(to); } if(tag[x])res=mincut[x]; else res=min(mincut[x],sum); tag[x]=0; head2[x]=0; return res; } bool cmp(int x,int y) { return dfn[x]<dfn[y]; } void solve() { int k; scanf("%lld",&k); for(int i=1;i<=k;i++) { scanf("%lld",&que[i]); tag[que[i]]=1; } sort(que+1,que+1+k,cmp); top=1; st[top]=que[1]; for(int i=2;i<=k;i++) { int now=que[i]; int lca=LCA(now,st[top]); while(1) { if(dep[lca]>=dep[st[top-1]]) //case1 or case2 or case3 { if(lca!=st[top])//case2 or case 3 { add(lca,st[top],0,e2,head2,e2_cnt); if(lca!=st[top-1])//case2 { st[top]=lca;//st.pop(top) and st.push(lca) } else //case3 { top--; } } // else : case 1 break; } else//case 4 { add(st[top-1],st[top],0,e2,head2,e2_cnt); top--; } } st[++top]=now;//case 1 2 3 4 } while(--top) { add(st[top],st[top+1],0,e2,head2,e2_cnt); } int ans=dfs2(st[1]); printf("%lld\n",ans); e2_cnt=1; } void work() { mincut[1]=inf; cin>>n; for(int i=1,x,y,w;i<n;i++) { scanf("%lld%lld%lld",&x,&y,&w); add(x,y,w,e1,head1,e1_cnt); add(y,x,w,e1,head1,e1_cnt); } dfs1(1); cin>>m; for(int i=1;i<=m;i++) { solve(); } } #undef int int main() { //freopen("P2495.in","r",stdin);//freopen("P2495.out","w",stdout); work(); }