BZOJ 2286 树链剖分+DFS序+虚树+树形DP
Posted yyjxx2010xyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(\'\\n\'); 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 }
以上是关于BZOJ 2286 树链剖分+DFS序+虚树+树形DP的主要内容,如果未能解决你的问题,请参考以下文章