bzoj 2286(洛谷 2495) [Sdoi2011]消耗战——虚树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2286

   https://www.luogu.org/problemnew/show/P2495

学习(抄)了 hzwer 的代码,觉得写得很好。http://hzwer.com/6188.html

有一个 “如果排序后第 i 个关键点和第 i-1 个关键点的 lca 是第 i-1 个关键点,就舍弃第 i 个关键点” 的操作,觉得很好。

把 hd[ ] 数组清空写在了 dfs 里,觉得很好。

自己一开始写了一个倍增找链上边权最小值,用来给虚树的边赋值,参考之后发现只要记录一个 “到根的路径上的最小边权” 就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
ll Mx(ll a,ll b){return a>b?a:b;}
ll Mn(ll a,ll b){return a<b?a:b;}

const int N=250005,K=20;const ll INF=3e10+5;//for dp
int n,hd[N],xnt,to[N<<1],nxt[N<<1],w[N<<1];
int dep[N],pre[N][K],bin[K],dfn[N],tim; ll mn[N];
bool cmp(int a,int b){return dfn[a]<dfn[b];}
void add(int x,int y,int z){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;}
void dfs(int cr,int fa)
{
  dfn[cr]=++tim; dep[cr]=dep[fa]+1;
  pre[cr][0]=fa;
  for(int t=1;bin[t]<=dep[cr];t++)
    pre[cr][t]=pre[pre[cr][t-1]][t-1];
  for(int i=hd[cr],v;i;i=nxt[i])
    if((v=to[i])!=fa)
      {
    mn[v]=Mn(mn[cr],w[i]);
    dfs(v,cr);
      }
}
int get_lca(int x,int y)
{
  if(dep[x]<dep[y])swap(x,y);
  int d=dep[x]-dep[y];
  for(int t=0;bin[t]<=d;t++)
    if(d&bin[t])x=pre[x][t];

  if(x==y)return x;
  for(int t=17;t>=0;t--)
    if(pre[x][t]!=pre[y][t])
      x=pre[x][t],y=pre[y][t];
  return pre[x][0];
}
namespace Tr{
  int hd[N],xnt,to[N],nxt[N];
  int p[N],tot,sta[N],top; ll dp[N];
  void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
  void get_tr()
  {
    xnt=0;
    sort(p+1,p+tot+1,cmp);
    int lm=tot; p[tot=1]=p[1];
    for(int i=2;i<=lm;i++)
      if(get_lca(p[i],p[tot])!=p[tot])p[++tot]=p[i];
    sta[top=1]=1;
    for(int i=1;i<=tot;i++)
      {
    int u=p[i], lca=get_lca(u,sta[top]);
    while(top&&dfn[lca]<dfn[sta[top]])
      {
        if(dfn[sta[top-1]]<dfn[lca])
          add(lca,sta[top]);
        else add(sta[top-1],sta[top]);
        top--;
      }
    if(sta[top]!=lca)sta[++top]=lca;
        sta[++top]=u;
      }
    for(int i=1;i<top;i++)add(sta[i],sta[i+1]);
  }
  void dfs(int cr)
  {
    if(!hd[cr]){dp[cr]=mn[cr];return;}
    dp[cr]=0;
    for(int i=hd[cr],v;i;i=nxt[i])
      {
    dfs(v=to[i]); dp[cr]+=dp[v];
      }
    hd[cr]=0;//////
    dp[cr]=Mn(dp[cr],mn[cr]);
  }
  void solve()
  {
    int k=rdn(); tot=0;
    for(int i=1,d;i<=k;i++)
      d=rdn(),p[++tot]=d;
    get_tr(); dfs(1); printf("%lld\n",dp[1]);
  }
}
int main()
{
  bin[0]=1;for(int i=1;i<=18;i++)bin[i]=bin[i-1]<<1;
  n=rdn();
  for(int i=1,u,v,z;i<n;i++)
    u=rdn(),v=rdn(),z=rdn(),add(u,v,z),add(v,u,z);
  mn[1]=INF; dfs(1,0);
  int Q=rdn(); while(Q--)Tr::solve();
  return 0;
}

 

posted on 2019-02-25 11:17  Narh  阅读(188)  评论(0编辑  收藏  举报

导航