bzoj2286 消耗战【虚树+树形dp】
来源:互联网 发布:js获取tr下的第一个td 编辑:程序博客网 时间:2024/06/07 03:55
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2286
解题思路:
假如只有一次询问,可以很好想到树形dp方程:
如果u是关键点,则f[u]=w(fa[u],u);
如果u不是关键点,则f[u]=min(w(fa[u],u),
但这样一次复杂度为O(n),则总复杂度为O(nm),显然超时。
像这种每次询问都给出多个关键点的题,应该建虚树,即每次询问都只把关键点及其两两之间的lca提出来另建一棵树,可以证明其规模为O(
新的dp方程为:
如果u是关键点,则f[u]=mi[u];
如果u不是关键点,则f[u]=min(mi[u],
其中mi[u]表示从根节点到u所经历的最小边权。
具体建虚树方法详见代码中的solve()函数,复杂度为O(
所以总复杂度为O(
注意要开long long。
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<queue>#include<vector>#define ll long longusing namespace std;int getint() { int i=0,f=1;char c; for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar()); if(c=='-')c=getchar(),f=-1; for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0'; return i*f;}const int N=250005;const ll INF=1e17;int n,m,idx,cnt;int dfn[N],dep[N],fa[N][20];int top,stk[N],vir[N],par[N];ll mi[N],f[N];bool key[N];bool cmp(const int &a,const int &b){ return dfn[a]<dfn[b];}struct tree{ int tot,first[N<<1],nxt[N<<1],to[N<<1]; ll w[N<<1]; inline void add(int x,int y,int z) { nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z; } inline void dfs (int u,ll val) { mi[u]=val; dfn[u]=++idx; for(int i=1;i<20;i++)fa[u][i]=fa[fa[u][i-1]][i-1]; for(int e=first[u];e;e=nxt[e]) { int v=to[e]; if(v==fa[u][0])continue; fa[v][0]=u; dep[v]=dep[u]+1; dfs(v,min(w[e],val)); } } inline void dp(int u) { ll res=0; for(int e=first[u];e;e=nxt[e]) { int v=to[e]; dp(v); res+=f[v]; } if(!key[u])f[u]=min(mi[u],res); else f[u]=mi[u]; }}tr,Vtr;int LCA(int x,int y){ if(dep[x]<dep[y])swap(x,y); int tmp=dep[x]-dep[y]; for(int i=0;i<20;i++) if(tmp&(1<<i))x=fa[x][i]; for(int i=19;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return x==y?x:fa[x][0];}void solve(){ cnt=getint();int t=cnt; for(int i=1;i<=cnt;i++)vir[i]=getint(); sort(vir+1,vir+cnt+1,cmp); while(top)--top; for(int i=1;i<=t;i++) { int u=vir[i]; if(!top) { par[u]=0; stk[++top]=u; continue; } int lca=LCA(stk[top],u); while(dep[stk[top]]>dep[lca]) { if(dep[stk[top-1]]<dep[lca]) par[stk[top]]=lca; --top; } if(lca!=stk[top]) { vir[++cnt]=lca; par[lca]=stk[top]; stk[++top]=lca; } par[u]=lca,stk[++top]=u; } Vtr.tot=0; for(int i=1;i<=cnt;i++) { int x=vir[i]; Vtr.first[x]=f[x]=0; if(i<=t)key[x]=1; else key[x]=0; } for(int i=1;i<=cnt;i++) { int x=vir[i]; if(par[x]) Vtr.add(par[x],x,0); } sort(vir+1,vir+cnt+1,cmp); int rt=vir[1]; //建虚树过程。 Vtr.dp(rt); cout<<f[rt]<<'\n';}int main(){ //freopen("lx.in","r",stdin); //freopen("lx1.out","w",stdout); int x,y,z; n=getint(); for(int i=1;i<=n;i++)mi[i]=INF; for(int i=1;i<n;i++) { x=getint(),y=getint(),z=getint(); tr.add(x,y,z),tr.add(y,x,z); } dep[1]=1;//dep[1]一定要设为1,不然建树出栈到top-1==0时会和dep[0]冲突。 tr.dfs(1,INF); m=getint(); while(m--) solve(); return 0;}
阅读全文
0 0
- bzoj2286 消耗战 虚树&树形dp
- bzoj2286 消耗战【虚树+树形dp】
- 虚树+树形dp bzoj2286【Sdoi2011】 消耗战
- BZOJ2286:消耗战(虚树,树形dp)
- [BZOJ2286][SDOI2011]消耗战(虚树+树形DP)
- BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
- 【虚树+树形DP】BZOJ2286(Sdoi2011)[消耗战]题解
- [BZOJ2286][Sdoi2011]消耗战(虚树+lca+树形dp)
- 【bzoj2286】【sdoi2011】【消耗战】【虚树+dp】
- 【bzoj2286】[Sdoi2011消耗战 虚树+dp
- [虚树dp] bzoj2286: Sdoi2011消耗战
- [虚树 + DP] BZOJ2286: [Sdoi2011]消耗战
- [BZOJ2286][Sdoi2011消耗战] 虚树
- BZOJ2286: [Sdoi2011]消耗战 虚树
- bzoj2286消耗战 虚树+树型动规
- BZOJ2286: [Sdoi2011]消耗战(虚树)
- 【BZOJ2286】【SDOI2011】消耗战 LCA单调性(构建虚树)+树形DP
- 【bzoj2286】 消耗战
- 给Jemter安装插件
- vue过渡效果的几种实现方法、各种滑动
- 微信小程序的跨平台图表库开发
- JavaScript中错误正确处理方式,你用对了吗?
- Vi文本编辑器的基本用法
- bzoj2286 消耗战【虚树+树形dp】
- Mybatis学习笔记(二)-----查询sql的配置文件
- php--- session
- struts2常用配置详解
- 优化HLS IP核的运行速度以及VIVADO工程中VDMA的配置
- compile WebKit in qt5.6(unfinished)
- 旋转图标
- 深度学习-基础知识学习笔记
- 如何将高程数据(等高线)转换成xi'an80或者beijing54坐标系