1. 程式人生 > >【BZOJ3522】【BZOJ4543】【POI2014】Hotel 樹形DP 長鏈剖分 啟發式合並

【BZOJ3522】【BZOJ4543】【POI2014】Hotel 樹形DP 長鏈剖分 啟發式合並

i++ memset cpp div include clear int down lis

題目大意

?  給你一棵樹,求有多少個組點滿足\(x\neq y,x\neq z,y\neq z,dist_{x,y}=dist_{x,z}=dist_{y,z}\)

?  \(1\leq n\leq 100000\)

題解

?  問題轉換為有多少個組點滿足\(dist_{i,x}=dist_{i,y}=dist_{i,z}\)

?  我們考慮樹形DP

?  \(f_{i,j}=\)\(i\)為根的子樹中與\(i\)的距離為\(j\)的節點數

?  \(g_{i,j}=\)\(i\)為根的子樹外選擇一個點\(s\)滿足\(s\)\(i\)的距離為\(j\),能新增的的方案數

?  若\(v\)\(u\)

的重兒子,則:\(f_{u,j}+=f_{v,j-1},g_{u,j}+=g_{v,j+1}\),這樣就可以由\(u\)的重兒子轉移到\(u\)

?  否則:\(g_{u,j}+=g_{v,{j+1}}+f_{v,j-1}\times f_{u,j},f_{u,j}+=f_{v,j-1}\)

?  答案為\(\sum f_{x,j}\times g_{y,j}\),其中\(x\)\(y\)的兄弟

?  可以用長鏈剖分輔助轉移

?  時間復雜度:\(O(n)\)

?  gjs大爺的長鏈剖分講解

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib> #include<ctime> #include<utility> using namespace std; typedef long long ll; typedef pair<int,int> pii; struct list { int v[200010]; int t[200010]; int h[100010]; int n; void clear() { n=0; memset(h,0,sizeof h); } void add(int
x,int y) { n++; v[n]=y; t[n]=h[x]; h[x]=n; } }; list l; ll ans; ll f[100010]; ll g[200010]; int d[100010]; int bg[100010]; int ed[100010]; int ch[100010]; int t[100010]; int w[100010]; int ti; void dfs(int x,int fa) { d[x]=1; ch[x]=0; int i; for(i=l.h[x];i;i=l.t[i]) if(l.v[i]!=fa) { dfs(l.v[i],x); if(d[l.v[i]]+1>d[x]) { d[x]=d[l.v[i]]+1; ch[x]=l.v[i]; } } } void dfs2(int x,int fa,int top) { t[x]=top; w[x]=++ti; if(x==top) bg[top]=ti; ed[top]=ti; if(ch[x]) dfs2(ch[x],x,top); int i; for(i=l.h[x];i;i=l.t[i]) if(l.v[i]!=ch[x]&&l.v[i]!=fa) dfs2(l.v[i],x,l.v[i]); } ll& getf(int x,int y) { return f[w[x]+y]; } ll& getg(int x,int y) { return g[2*(w[t[x]]-1)+2*d[t[x]]-d[x]+1-y]; } void solve(int x,int fa) { if(ch[x]) solve(ch[x],x); int i,j; for(i=l.h[x];i;i=l.t[i]) if(l.v[i]!=fa&&l.v[i]!=ch[x]) { int v=l.v[i]; solve(v,x); for(j=0;j<d[v];j++) ans+=getf(v,j)*getg(x,j+1); for(j=1;j<d[v];j++) ans+=getg(v,j)*getf(x,j-1); for(j=0;j<d[v];j++) getg(x,j+1)+=getf(v,j)*getf(x,j+1); for(j=1;j<d[v];j++) getg(x,j-1)+=getg(v,j); for(j=0;j<d[v];j++) getf(x,j+1)+=getf(v,j); } ans+=getg(x,0); getf(x,0)++; } int main() { int n; scanf("%d",&n); l.clear(); memset(bg,0,sizeof bg); memset(ed,0,sizeof ed); memset(f,0,sizeof f); memset(g,0,sizeof g); memset(d,0,sizeof d); memset(ch,0,sizeof ch); memset(t,0,sizeof t); memset(w,0,sizeof w); ans=0; ti=0; int i,x,y; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); l.add(x,y); l.add(y,x); } dfs(1,0); dfs2(1,0,1); solve(1,0); printf("%lld\n",ans); return 0; }

【BZOJ3522】【BZOJ4543】【POI2014】Hotel 樹形DP 長鏈剖分 啟發式合並