[虚树 + DP] BZOJ2286: [Sdoi2011]消耗战
来源:互联网 发布:mac磁盘可清除怎么清除 编辑:程序博客网 时间:2024/09/21 06:37
虚树入门题。
所谓虚树就是只保留需要的关键节点及互相的lca进行重建树,在虚树上跑DP之类的,使得复杂度与关键点个数相关,而且可能能简化问题。
虚树的建法是按dfs序的顺序加入,维护一个当前链的栈,类似dfs一样搞搞就好了。网上有一些资料…
建虚树代码:
void buildVT(){ inT.clear(); sort(S.begin(),S.end(),_cmp); stk[top=1]=1; inT.push_back(1); for(int i=0;i<S.size();i++){ int x=S[i], _lca=LCA(x,stk[top]); inT.push_back(x); inT.push_back(_lca); while(top>1&&dfn[stk[top-1]]>dfn[_lca]) Vadd(stk[top-1],stk[top]), top--; if(top==1||stk[top]==_lca){ stk[++top]=x; continue; } if(stk[top-1]==_lca) Vadd(stk[top-1],stk[top]), top--; else Vadd(_lca,stk[top]), stk[top]=_lca; stk[++top]=x; } while(top>1) Vadd(stk[top-1],stk[top]), top--;}
这题树形DP很显然,建好虚树的边权是对应原树中链上最小边…
#include<cstdio>#include<vector>#include<algorithm>using namespace std;typedef long long LL;const int maxn=300005,maxe=600005,maxq=300005;int n,Q,Tim,dfn[maxn],fir[maxn],nxt[maxe],son[maxe],w[maxe],tot;void add(int x,int y,int z){ son[++tot]=y; w[tot]=z; nxt[tot]=fir[x]; fir[x]=tot;}int dep[maxn],anc[maxn][20],_min[maxn][20];void dfs_info(int x,int pre,int w_pre){ dfn[x]=++Tim; anc[x][0]=pre; _min[x][0]=w_pre; for(int i=1;i<=18;i++) anc[x][i]=anc[anc[x][i-1]][i-1], _min[x][i]=min(_min[x][i-1],_min[anc[x][i-1]][i-1]); for(int j=fir[x];j;j=nxt[j]) if(son[j]!=pre){ dep[son[j]]=dep[x]+1; dfs_info(son[j],x,w[j]); }}int LCA(int x,int y){ if(dep[x]<dep[y]) swap(x,y); for(int i=18;i>=0;i--) if(dep[anc[x][i]]>=dep[y]) x=anc[x][i]; if(x==y) return x; for(int i=18;i>=0;i--) if(anc[x][i]!=anc[y][i]) x=anc[x][i], y=anc[y][i]; return anc[x][0];}vector<int> S,inT;int _cmp(int A,int B){ return dfn[A]<dfn[B]; }int stk[maxn],top,vfir[maxn],vnxt[maxe],vw[maxn],vson[maxe],vtot;int Query_min(int x,int y){ int res=1e9; for(int i=18;i>=0;i--) if(dep[anc[x][i]]>=dep[y]) res=min(res,_min[x][i]), x=anc[x][i]; return res;}void Vadd(int x,int y){ vson[++vtot]=y; vw[vtot]=Query_min(y,x); vnxt[vtot]=vfir[x]; vfir[x]=vtot; //printf("%d --- %d %d\n",x,y,vw[vtot]);}void buildVT(){ inT.clear(); sort(S.begin(),S.end(),_cmp); stk[top=1]=1; inT.push_back(1); for(int i=0;i<S.size();i++){ int x=S[i], _lca=LCA(x,stk[top]); inT.push_back(x); inT.push_back(_lca); while(top>1&&dfn[stk[top-1]]>dfn[_lca]) Vadd(stk[top-1],stk[top]), top--; if(top==1||stk[top]==_lca){ stk[++top]=x; continue; } if(stk[top-1]==_lca) Vadd(stk[top-1],stk[top]), top--; else Vadd(_lca,stk[top]), stk[top]=_lca; stk[++top]=x; } while(top>1) Vadd(stk[top-1],stk[top]), top--;}int b[maxn];LL f[maxn];bool vis[maxn];void dfs_dp(int x,int pre){ if(vis[x]) f[x]=1e18; else{ f[x]=0; for(int j=vfir[x];j;j=vnxt[j]) if(vson[j]!=pre) dfs_dp(vson[j],x), f[x]+=min(f[vson[j]],(LL)vw[j]); }}void Solve(){ S.clear(); scanf("%d",&b[0]); for(int i=1;i<=b[0];i++) scanf("%d",&b[i]), S.push_back(b[i]), vis[b[i]]=true; buildVT(); dfs_dp(1,1); printf("%lld\n",f[1]); for(int i=1;i<=b[0];i++) vis[b[i]]=false; vtot=0; for(int i=0;i<inT.size();i++) vfir[inT[i]]=0;}int main(){ freopen("bzoj2286.in","r",stdin); freopen("bzoj2286.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n-1;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } dfs_info(1,1,1e9); scanf("%d",&Q); while(Q--) Solve(); return 0;}
阅读全文
0 0
- 【bzoj2286】【sdoi2011】【消耗战】【虚树+dp】
- 【bzoj2286】[Sdoi2011消耗战 虚树+dp
- [虚树dp] bzoj2286: Sdoi2011消耗战
- [虚树 + DP] BZOJ2286: [Sdoi2011]消耗战
- 虚树+树形dp bzoj2286【Sdoi2011】 消耗战
- [BZOJ2286][SDOI2011]消耗战(虚树+树形DP)
- BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
- 【虚树+树形DP】BZOJ2286(Sdoi2011)[消耗战]题解
- [BZOJ2286][Sdoi2011消耗战] 虚树
- BZOJ2286: [Sdoi2011]消耗战 虚树
- BZOJ2286: [Sdoi2011]消耗战(虚树)
- [BZOJ2286][Sdoi2011]消耗战(虚树+lca+树形dp)
- bzoj2286: [Sdoi2011]消耗战
- bzoj2286[Sdoi2011消耗战
- [BZOJ2286] [Sdoi2011]消耗战
- [BZOJ2286][SDOI2011]消耗战
- BZOJ2286: [Sdoi2011]消耗战
- bzoj2286: [Sdoi2011消耗战
- 机器学习评估方法——P值校验
- 深度机器学习中的batch
- missing artifact com.oracle:ojdbc14:jar:10.2.0.2.0解决办法
- 七牛云存储域名配置
- 文件上传三种方式
- [虚树 + DP] BZOJ2286: [Sdoi2011]消耗战
- PMP笔记-产品核实、范围核实及质量控制的区别
- HDU 2212 DFS【思维】
- ubuntu重装的一些问题
- ARP和普通代理ARP
- 在VS2013和GCC中都使用中文
- sql的经典我是道题
- 蓝桥杯:分解质因数
- Pip