[bzoj4543][bzoj3522][DP][長鏈剖分]Hotel&Hotel加強版
Description
有一個樹形結構的賓館,n個房間,n-1條無向邊,每條邊的長度相同,任意兩個房間可以相互到達。吉麗要給他的三個妹子各開(一個)房(間)。三個妹子住的房間要互不相同(否則要打起來了),為了讓吉麗滿意,你需要讓三個房間兩兩距離相同。
有多少種方案能讓吉麗滿意?
Input
第一行一個數n。 接下來n-1行,每行兩個數x,y,表示x和y之間有一條邊相連。
Output
讓吉麗滿意的方案數。
Sample Input
7
1 2
5 7
2 5
2 3
5 6
4 5
Sample Output
5
HINT
【樣例解釋】
{1,3,5},{2,4,6},{2,4,7},{2,6,7},{4,6,7}
【資料範圍】
n≤5000
題解
首先有個性質
這三個點的路徑會交於一點,三個點到這個點的距離都相等且位於同一棵子樹
那麼 的就可以直接做了…
這個 的有點神仙…
設一個dp狀態
表示 點子樹中有多少距離為 的點
表示 點子樹中,有多少對,在 的子樹外面找一個距離為 的點就能構成一個合法三元組的數量
每掃到一棵子樹
可以這樣累加答案
然後更新這樣更新
注意到這樣是 的
考慮如何優化
我們發現,每個點的第一次轉移其實就是找一個兒子,讓他的 陣列左移一位, 陣列右移一位
指標移動即可
這樣可以節省 的複雜度
長鏈剖分,每個點選擇它的重兒子做更新
其他兒子暴力更新
單考慮重鏈上的轉移,一次是 的,所以總複雜度不會超過
再考慮輕邊,每條重鏈只會在頭的位置被計算完整個重鏈的長度
顯然重鏈沒有重疊
所以輕邊的轉移總複雜度也是 的
於是就是 的優秀複雜度了…
空間的話…學習了一下別人的開法畢竟不會指標陣列這個東西
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
struct node{int y,next;}a[210000];int len,last[110000];
void ins(int x,int y){len++;a[len].y=y;a[len].next=last[x];last[x]=len;}
LL spa[100005*10];
LL *f[100005],*g[100005],*now=spa+100005,ans;
int dep[100005],son[100005];
void init(int x,int fa)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa)
{
init(y,x);
if(dep[y]>dep[son[x]])son[x]=y;
}
}
dep[x]=dep[son[x]]+1;
}
void newnode(int x)
{
f[x]=now;now=now+2*dep[x]+1;
g[x]=now;now=now+2*dep[x]+1;
}
void dp(int x,int fa)
{
f[x][0]=1;
if(son[x])
{
f[son[x]]=f[x]+1;g[son[x]]=g[x]-1;
dp(son[x],x);
ans+=g[son[x]][1];
}
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa&&y!=son[x])
{
newnode(y);dp(y,x);
for(int j=dep[y];j>=0;j--)
{
if(j)ans=ans+g[y][j]*f[x][j-1];
ans=ans+g[x][j+1]*f[y][j];
g[x][j+1]+=f[x][j+1]*f[y][j];
}
for(int j=dep[y];j>=0;j--)
{
if(j)g[x][j-1]+=g[y][j];
f[x][j+1]+=f[y][j];
}
}
}
}
int n;
int main()
{
n=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
ins(x,y);ins(y,x);
}
init(1,0);
newnode(1);
dp(1,0);
pr2(ans);
return 0;
}