[SDOI2011][bzoj2286] 消耗战 [虚树+dp]
2018-03-14 20:38
549 查看
[b]题面:[/b]
传送门
[b]思路:[/b]
看到所有询问中的点数总和是十万级别的,就想到用虚树~\(≧▽≦)/~啦
首先,树形dp应该是很明显可以看出来的:
设dp[u]表示以u为根的子树(不包括u)中的宝藏岛全部切断的最小需要值
那么显然dp[u]等于所有dp[v]的和(v是u的儿子)与从根(一号结点)到u的路径上的最小边权之间的最小值
然后dp[1]就是答案了
建出虚树然后dp,$O\left(n\right)$解决
[b]Code:[/b]
传送门
[b]思路:[/b]
看到所有询问中的点数总和是十万级别的,就想到用虚树~\(≧▽≦)/~啦
首先,树形dp应该是很明显可以看出来的:
设dp[u]表示以u为根的子树(不包括u)中的宝藏岛全部切断的最小需要值
那么显然dp[u]等于所有dp[v]的和(v是u的儿子)与从根(一号结点)到u的路径上的最小边权之间的最小值
然后dp[1]就是答案了
建出虚树然后dp,$O\left(n\right)$解决
[b]Code:[/b]
/#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cassert> #define ll long long using namespace std; const long long inf=(1ll<<50ll); inline ll read(){ ll re=0,flag=1;char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') flag=-1; ch=getchar(); } while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); return re*flag; } ll n,m,dep[250010],fa[250010],st[250010][20],dfn[250010],clk,minn[250010]; struct graph{ ll first[250010],cnt; struct edge{ ll to,next,w; }a[500010]; inline void add(ll u,ll v,ll w){ if(u==v) return; a[++cnt]=(edge){v,first[u],w};first[u]=cnt; } void init(){ cnt=0; } }G,g; void dfs(ll u,ll f){ ll i,v;fa[u]=st[u][0]=f;dfn[u]=++clk;dep[u]=dep[f]+1; for(i=G.first[u];~i;i=G.a[i].next){ v=G.a[i].to; if(v==f) continue; minn[v]=min(minn[u],G.a[i].w); dfs(v,u); } } void ST(){ ll i,j; for(j=1;j<=19;j++){ for(i=1;i<=n;i++) st[i][j]=st[st[i][j-1]][j-1]; } } ll lca(ll l,ll r){ if(dep[l]>dep[r]) swap(l,r); ll i; for(i=19;i>=0;i--) if(dep[st[r][i]]>=dep[l]) r=st[r][i]; if(l==r) return l; for(i=19;i>=0;i--) if(st[l][i]!=st[r][i]){ l=st[l][i]; r=st[r][i]; } return fa[l]; } ll q[250010],tot,s[250010],top,num,f[250010]; bool cmp(ll l,ll r){ return dfn[l]<dfn[r]; } void dp(ll u){ ll i,v,tmp=0; for(i=g.first[u];~i;i=g.a[i].next){ v=g.a[i].to;g.first[u]=g.a[i].next; dp(v);tmp+=f[v]; } if(!tmp) f[u]=minn[u]; else f[u]=min(minn[u],tmp); } int main(){ ll i,t1,t2,t3,j; n=read();memset(G.first,-1,sizeof(G.first)); for(i=1;i<n;i++){ t1=read();t2=read();t3=read(); G.add(t1,t2,t3);G.add(t2,t1,t3); } minn[1]=inf; dfs(1,0);ST(); m=read();memset(g.first,-1,sizeof(g.first)); for(i=1;i<=m;i++){ tot=read();//memset(q,0,sizeof(q)); for(j=1;j<=tot;j++) q[j]=read(),assert(q[j]<=n); sort(q+1,q+tot+1,cmp);g.init(); num=0;q[++num]=q[1]; for(j=2;j<=tot;j++) if(lca(q[j],q[num])!=q[num]) q[++num]=q[j]; s[++top]=1;ll grand; for(j=1;j<=num;j++){ if(q[j]==0) return *(int*)0; grand=lca(q[j],s[top]); while(1){ if(dep[s[top-1]]<=dep[grand]){ g.add(grand,s[top--],0); if(s[top]!=grand) s[++top]=grand; break; } g.add(s[top-1],s[top],0);top--; } if(s[top]!=q[j]) s[++top]=q[j]; } while(--top) g.add(s[top],s[top+1],0); dp(1); printf("%lld\n",f[1]); } }
相关文章推荐
- 【BZOJ2286】消耗战(SDOI2011)-虚树+树形DP
- 【BZOJ】2286: [Sdoi2011消耗战【虚树DP】
- BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
- BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
- BZOJ 2286 [Sdoi2011]消耗战(虚树+树形DP)
- 【虚树+树形DP】BZOJ2286(Sdoi2011)[消耗战]题解
- BZOJ2286 [Sdoi2011]消耗战 (虚树 + 树形DP)
- [BZOJ2286][Sdoi2011]消耗战(虚树+lca+树形dp)
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
- [BZOJ2286][SDOI2011]消耗战(虚树+树形DP)
- bzoj 2286 SDOI2011 消耗战 虚树dp
- bzoj 2286: [Sdoi2011消耗战 虚树+树形dp
- [bzoj2286][Sdoi2011]消耗战(虚树上的DP)
- bzoj 2286 [Sdoi2011]消耗战(虚树+树上DP)
- [虚树+树形DP]BZOJ 2286—— [Sdoi2011]消耗战
- 【 bzoj 2286 】 : [Sdoi2011]消耗战 - 树形DP
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
- 【BZOJ2286】【SDOI2011】消耗战 [虚树][树形DP]
- bzoj 2286: [Sdoi2011消耗战 (虚树+树形DP)
- 【bzoj2286】【sdoi2011】【消耗战】【虚树+dp】