BZOJ 2286 树链剖分+DFS序+虚树+树形DP

第一次学习虚树,就是把无关的点去掉。S里维护一条链即可。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #define LL long long
  6 using namespace std;
  7 const LL Maxm=501000;
  8 const LL Maxn=250100;
  9 const LL Inf=1e60;
 10 struct Node {LL to,next,w;}edge[Maxm],edge2[Maxm];
 11 LL head[Maxn],head2[Maxn],dep[Maxn],H[Maxn],mark[Maxn],size[Maxn];
 12 LL top[Maxn],father[Maxn],f[Maxn],S[Maxn],mn[Maxn];
 13 LL cnt1,cnt2,tot,n,u,v,w,tp,m,K;
 14 bool vis[Maxn];
 15 inline void Add(LL u,LL v,LL w)
 16 {edge[cnt1].to=v;edge[cnt1].next=head[u];edge[cnt1].w=w;head[u]=cnt1++;
 17 edge[cnt1].to=u;edge[cnt1].next=head[v];edge[cnt1].w=w;head[v]=cnt1++;}
 18 inline void Add2(LL u,LL v)
 19 {if (u==v) return; edge2[cnt2].to=v;edge2[cnt2].next=head2[u];head2[u]=cnt2++;}
 20 inline LL Min(LL x,LL y) {return x>y?y:x;}
 21 inline void Get_Int(LL &x)
 22 {
 23     x=0;  char ch=getchar(); LL f=1;
 24     while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
 25     while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} x*=f;
 26 }
 27 inline void Put_Int(LL x)
 28 {
 29     char ch[20];  LL top=0;
 30     if (x==0) ch[++top]='0';
 31     while (x) ch[++top]=x%10+'0',x/=10;
 32     while (top) putchar(ch[top--]); putchar('
');
 33 }
 34 //================================================
 35 void Dfs1(LL u)
 36 {
 37     mark[u]=++tot;vis[u]=true; size[u]=1;
 38     for (LL i=head[u];i!=-1;i=edge[i].next)
 39         if (!vis[edge[i].to])
 40         {
 41             dep[edge[i].to]=dep[u]+1;
 42             father[edge[i].to]=u;
 43             mn[edge[i].to]=Min(mn[u],edge[i].w);
 44             Dfs1(edge[i].to);
 45             size[u]+=size[edge[i].to];
 46         }
 47 }
 48 void Dfs2(LL u,LL chain)
 49 {
 50     top[u]=chain; vis[u]=true; LL k=0;
 51     for (int i=head[u];i!=-1;i=edge[i].next)
 52         if (!vis[edge[i].to] && (size[edge[i].to]>size[k] || k==0)) k=edge[i].to;
 53     if (k==0) return;
 54     Dfs2(k,chain);
 55     for (int i=head[u];i!=-1;i=edge[i].next)
 56         if (!vis[edge[i].to] && i!=k) Dfs2(edge[i].to,edge[i].to);
 57 }
 58 inline LL Lca(LL u,LL v)
 59 {
 60     while (true)
 61     {
 62         if (top[u]==top[v]) return dep[u]>dep[v]?v:u;
 63         if (dep[top[u]]>dep[top[v]]) u=father[top[u]]; 
 64         else v=father[top[v]];
 65     }
 66 }
 67 //=============================================================
 68 inline bool cmp(LL x,LL y) {return mark[x]<mark[y];}
 69 void Dp(LL u)
 70 {
 71 
 72     vis[u]=true; f[u]=mn[u]; LL ret=0;
 73     for (int i=head2[u];i!=-1;i=edge2[i].next)
 74     {
 75         Dp(edge2[i].to);
 76         ret+=f[edge2[i].to];
 77     }
 78     head2[u]=-1;
 79     if (ret) f[u]=Min(f[u],ret);
 80 }
 81 void Solve() 
 82 {
 83     Get_Int(K);
 84     for (int i=1;i<=K;i++) Get_Int(H[i]);
 85     sort(H+1,H+K+1,cmp);
 86     tp=tot=0; H[++tot]=H[1];
 87     for (int i=2;i<=K;i++) 
 88         if (Lca(H[tot],H[i])!=H[tot]) H[++tot]=H[i];
 89     cnt2=0;
 90     S[++tp]=1;
 91     for (int i=1;i<=tot;i++)
 92     {
 93         LL u=H[i],f=Lca(u,S[tp]);
 94         while (true)
 95         {
 96             if (dep[f]>=dep[S[tp-1]])
 97             {
 98                 Add2(f,S[tp--]);
 99                 if (S[tp]!=f) S[++tp]=f;
100                 break;
101             }
102             Add2(S[tp-1],S[tp]); tp--;
103         }
104         if (S[tp]!=u) S[++tp]=u;
105     }
106     while (--tp) Add2(S[tp],S[tp+1]);
107     Dp(1);
108     Put_Int(f[1]);
109 }
110 int main()
111 {
112     Get_Int(n);
113     memset(head,-1,sizeof(head));cnt1=0;
114     for (int i=1;i<n;i++)
115     {
116         Get_Int(u),Get_Int(v),Get_Int(w);
117         Add(u,v,w),Add(v,u,w);
118     }
119 
120     father[1]=1; dep[1]=1; tot=0; mn[1]=Inf;
121     memset(vis,false,sizeof(vis));Dfs1(1);
122     memset(vis,false,sizeof(vis));Dfs2(1,1);
123     memset(head2,-1,sizeof(head2));
124     Get_Int(m);
125     for (int i=1;i<=m;i++) Solve();
126     return 0;
127 }
C++
原文地址:https://www.cnblogs.com/yyjxx2010xyu/p/5517715.html