标签:入栈 cos sdoi2011 优化 span alt cout turn sync
虚树对于多次询问的时候有这优化复杂度的好处,其原理就是只保留有用节点和必须保留的有用节点的lca
先求一遍dfs序后,用栈模拟操作,根据lca是否在栈中确定是否要将lca加入栈,因为重构了树,因此原来的边的信息需要进行更换
对于本题,新的边其实就是路径上的边权的最小值,这是因为随便切掉一个边就能把他们断开。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+10; const int mod=998244353; struct node{ int x; ll w; }; vector<node> g[N],g1[N]; int n; int dfn[N],times; int f[N][25],depth[N]; ll cost[N][25]; int st[N]; int cnt[N]; int q[N]; ll dp[N]; void dfs(int u,int fa,ll w){ dfn[u]=++times; depth[u]=depth[fa]+1; f[u][0]=fa;cost[u][0]=w; int i; for(i=1;i<=21;i++){ f[u][i]=f[f[u][i-1]][i-1]; cost[u][i]=min(cost[f[u][i-1]][i-1],cost[u][i-1]); } for(i=0;i<g1[u].size();i++){ int v=g1[u][i].x; if(v==fa) continue; dfs(v,u,g1[u][i].w); } } bool cmp(int x,int y){ return dfn[x]<dfn[y]; } int lca(int a,int b){ if(depth[a]<depth[b]) swap(a,b); int i; for(i=21;i>=0;i--){ if(depth[f[a][i]]>=depth[b]){ a=f[a][i]; } } if(a==b) return a; for(i=21;i>=0;i--){ if(f[a][i]!=f[b][i]){ a=f[a][i]; b=f[b][i]; } } return f[a][0]; } ll query(int a,int b){ ll ans=1e18; if(depth[a]>depth[b]) swap(a,b); for(int i=21;i>=0;i--){ if(depth[f[b][i]]>=depth[a]){ ans=min(ans,cost[b][i]); b=f[b][i]; } } return ans; } void add(int a,int b){ ll num=query(a,b); g[a].push_back({b,num}); } void get(int u){ int i; for(i=0;i<g[u].size();i++){ int v=g[u][i].x; get(v); if(st[v]) dp[u]+=g[u][i].w; else dp[u]+=min(g[u][i].w,dp[v]); st[v]=0;dp[v]=0; } g[u].clear(); } int main(){ ios::sync_with_stdio(false); int i; cin>>n; for(i=1;i<n;i++){ int a,b,c; cin>>a>>b>>c; g1[a].push_back({b,c}); g1[b].push_back({a,c}); } //cout<<"aa"<<endl; dfs(1,0,0); int m; cin>>m; while(m--){ int k; cin>>k; for(i=1;i<=k;i++){ int x; cin>>x; st[x]=1; cnt[i]=x; } sort(cnt+1,cnt+1+k,cmp); q[1]=1; int tt=1; for(i=1;i<=k;i++){ if(cnt[i]==1) continue; int p=lca(cnt[i],q[tt]); if(p!=q[tt]){ while(dfn[p]<dfn[q[tt-1]]){ add(q[tt-1],q[tt]); tt--; } if(dfn[p]!=dfn[q[tt-1]]){ add(p,q[tt]); q[tt]=p; } else{ add(p,q[tt]); tt--; } } q[++tt]=cnt[i]; } for(i=1;i<tt;i++){ add(q[i],q[i+1]); } get(1); cout<<dp[1]<<endl; dp[1]=0; } return 0; }
标签:入栈 cos sdoi2011 优化 span alt cout turn sync
原文地址:https://www.cnblogs.com/ctyakwf/p/13360623.html