• 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
    ",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;
    }
  • 相关阅读:
    Beta 冲刺(7/7)
    Beta 冲刺(6/7)
    Beta 冲刺(5/7)
    Beta 冲刺(4/7)
    Beta 冲刺(3/7)
    Beta 冲刺(2/7)
    Beta 冲刺(1/7)
    福大软工 · 第十次作业
    Adobe acrobat DC 2020 激活方法
    物理八年级下册2
  • 原文地址:https://www.cnblogs.com/Narh/p/10429853.html
Copyright © 2020-2023  润新知