【長鏈剖分】【DP】BZOJ4543[POI2014]Hotel加強版
阿新 • • 發佈:2019-01-08
題意:
給出一棵 n 個點的無根樹,請在這棵樹上選三個互不相同的節點,使得這個三個
節點兩兩之間距離相等,輸出方案數即可。
分析:
定義
設
表示在以x為根的子樹中,與x距離為i的節點數
表示在以x為根的子樹中選擇了兩個節點,最後一個點需滿足與x的距離為i的方案數。
所以
可以通過繼承其最大兒子的DP值,使其最大兒子的轉移速度為O(1),再O(n)暴力列舉每個輕兒子的最大深度。
繼承的具體操作,可以通過預開記憶體的方式實現。
(即建立一個記憶體池,然後f(x)從
位置開始,
就從
位置開始,g(x)從i位置開始,
就從i-1位置開始,詳見程式碼中兩個dfs)
總的複雜度為
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
typedef long long ll;
vector<int> a[MAXN];
ll Gpool[MAXN*2];
ll Fpool[MAXN];
ll *f[MAXN],*g[MAXN],*fcnt=Fpool,*gcnt=Gpool;
int maxl[MAXN],son[MAXN];
void prepare(int x,int fa=0){
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(u==fa)
continue;
prepare(u,x);
maxl[x]=max(maxl[x],maxl[u]+1);
}
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(u==fa)
continue;
if(son[x]==0||maxl[u]>maxl[son[x]])
son[x]=u;
}
}
void dfsf(int x,int fa=0){
f[x]=++fcnt;
if(son[x])
dfsf(son[x],x);
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(u==fa||u==son[x])
continue;
dfsf(u,x);
}
}
void dfsg(int x,int fa=0){
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(u==fa||u==son[x])
continue;
dfsg(u,x);
gcnt+=maxl[u];
}
if(son[x])
dfsg(son[x],x);
g[x]=++gcnt;
}
ll ans;
void dp(int x,int fa=0){
f[x][0]=1;
if(son[x]==0)
return ;
dp(son[x],x);
ans+=g[x][0];
for(int i=0;i<int(a[x].size());i++){
int u=a[x][i];
if(u==fa||u==son[x])
continue;
dp(u,x);
for(int i=1;i<=maxl[u]+1;i++)
ans+=g[x][i]*f[u][i-1];
for(int i=0;i<=maxl[u]-1;i++)
ans+=f[x][i]*g[u][i+1];
for(int i=0;i<=maxl[u]-1;i++)
g[x][i]+=g[u][i+1];
for(int i=1;i<=maxl[u]+1;i++)
g[x][i]+=(f[u][i-1]*f[x][i]);
for(int i=1;i<=maxl[u]+1;i++)
f[x][i]+=f[u][i-1];
}
// PF("%d %d(%lld):\n",x,maxl[x],ans);
// for(int i=0;i<=maxl[x];i++)
// PF("%d:[%lld %lld]\n",i,f[x][i],g[x][i]);
// PF("-------------------\n");
}
int n,u,v;
void init(){
fcnt=Fpool;
gcnt=Gpool;
memset(Fpool,0,sizeof Fpool);
memset(Gpool,0,sizeof Gpool);
memset(maxl,0,sizeof maxl);
memset(son,0,sizeof son);
for(int i=1;i<=n;i++)
a[i].clear();
ans=0;
}
int main(){
// freopen("three1-3.in","r",stdin);
while(SF("%d",&n)!=EOF){
if(n==0)
break;
init();
for(int i=1;i<n;i++){
SF("%d%d",&u,&v);
a[u].push_back(v);
a[v].push_back(u);
}
prepare(1);
dfsf(1);
dfsg(1);
dp(1);
PF("%lld\n",ans);
}
}