Luogu P2495 [SDOI2011]消耗战

Posted jackpei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P2495 [SDOI2011]消耗战相关的知识,希望对你有一定的参考价值。

虚树+DP

每个点记录自己到根路径上的最小边权 (mn[u]) ;DP时初始化 (ans[u]=sumlimits_{vin son_u} ans[v]) ,如果是关键点则 (u) 的答案 (ans[u]=mn[u]) ,若不是关键点则 (ans[u]=min(ans[u],mn[u]))

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=250010; const ll Inf=1e15;
int n,m,k;
int d[N],dfn[N],h[N],stk[N],pre[N],son[N],sz[N],top[N],t,num;
ll ans[N],mn[N];
bool vis[N];
int vr[N<<1],nxt[N<<1],fir[N],w[N<<1],cnt;
inline void add(int u,int v,int ww) 
  {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,w[cnt]=ww;}
inline void dfs(int u) {
  dfn[u]=++num,sz[u]=1;
  for(R i=fir[u];i;i=nxt[i]) {
    R v=vr[i];
    if(d[v]) continue;
    mn[v]=min(mn[u],(ll)w[i]),d[v]=d[u]+1,pre[v]=u;
    dfs(v); sz[u]+=sz[v];
    if(sz[son[u]]<sz[v]) son[u]=v;
  }
}
inline void dfs2(int u,int tp) {
  top[u]=tp;
  if(son[u]) dfs2(son[u],tp);
  for(R i=fir[u];i;i=nxt[i]) {
    R v=vr[i];
    if(!top[v]) dfs2(v,v);
  }
}
inline int lca(int u,int v) {
  while(top[u]!=top[v]) {
    if(d[top[u]]<d[top[v]]) swap(u,v);
    u=pre[top[u]];
  } return d[u]<d[v]?u:v;
}
inline void dp(int u) {
  ans[u]=0;
  for(R i=fir[u];i;i=nxt[i]) {
    R v=vr[i];
    dp(v);
    ans[u]+=ans[v];
  } 
  if(vis[u]) ans[u]=mn[u];
  else ans[u]=min(ans[u],(ll)mn[u]);
  fir[u]=0;
}
inline bool cmp(const int& a,const int& b) 
  {return dfn[a]<dfn[b];}
inline void main() {
  n=g();
  for(R i=1,u,v,w;i<n;++i) 
    u=g(),v=g(),w=g(),add(u,v,w),add(v,u,w);
  mn[1]=Inf,d[1]=1,dfs(1),num=0,dfs2(1,0);
  memset(fir,0,n+1<<2);
  m=g(); while(m--) {
    k=g(); for(R i=1;i<=k;++i) 
      h[i]=g(),vis[h[i]]=true;
    sort(h+1,h+k+1,cmp);
    cnt=0,fir[1]=0;
    R top;
    stk[top=1]=1; 
    for(R i=1+(h[1]==1),l;i<=k;++i) {
      l=lca(stk[top],h[i]);
      if(l!=stk[top]) {
        while(dfn[l]<dfn[stk[top-1]]) {
          lca(stk[top-1],stk[top]);
          add(stk[top-1],stk[top],0);
          --top;
        }
        if(dfn[l]>dfn[stk[top-1]]) {
          lca(l,stk[top]);
          add(l,stk[top],0),stk[top]=l;
        }
        else lca(l,stk[top]),add(l,stk[top--],0);
      }
      stk[++top]=h[i];
    }
    for(R i=1;i<top;++i) 
      lca(stk[i],stk[i+1]),add(stk[i],stk[i+1],0);
    dp(1),printf("%lld
",ans[1]);
    for(R i=1;i<=k;++i) vis[h[i]]=0;
  }
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.18

以上是关于Luogu P2495 [SDOI2011]消耗战的主要内容,如果未能解决你的问题,请参考以下文章

●洛谷P2495 [SDOI2011]消耗战

AC日记——[SDOI2011]消耗战 洛谷 P2495

P2495 [SDOI2011]消耗战

P2495 [SDOI2011]消耗战 (虚树)

P2495 [SDOI2011]消耗战

洛谷 P2495 [SDOI2011]消耗战