title
Enhanced: BZOJ 4543
Simplify the meaning of the questions:
Has a tree structure, the same length of each side of any two nodes can reach each other.
Option 3 points, equal twenty-two distance, how many kinds of programs?
\(n\leqslant 5000\)
Enhanced: \ (the n-\ leqslant 1E5 \)
analysis
Significantly tree \ (Dp \) , and will be apparent to any two points three points must coincide midpoint, the intermediate node can be enumerated.
State as follows:
- \ (f1 [j] \) represented by \ (I \) subtree rooted at the node number of a selected depth depth \ (J \) of the program number of nodes.
- \ (f2 [j] \) represented by \ (I \) subtree rooted at the node number depth of two selected depth \ (J \) number of nodes of the program.
- \ (f3 [j] \) represented by \ (I \) subtree rooted at the node number depth of three selected depth \ (J \) number of nodes of the program.
State transition to the principle of multiplying with multiplication, then they can accumulate.
Enhanced Edition:
Enumeration midpoint of the way does not work, we need to put it another thought.
Think of ways \ (Dp \) at:
Set \ (f [i] [j ] \) represented by \ (I \) is the subtree rooted to \ (I \) distance \ (J \) of the number of points.
Set \ (g [i] [j ] \) represented by \ (I \) is the root of the subtree in which the number of points may subtree \ (I \) outside, and the \ (I \) the distance \ (j \) is the number of dots to meet the meaning of the title triples.
\ (Dp \) when: each addition \ (I \) of a child \ (K \) after the promoter, to update answer:
\ [ANS = ANS + \ SUM ^ of N_ {J = 0} F [I] [J ] * g [k] [j + 1] + {j = 0} g [i \ sum ^ n_] [j] * f [k] \]
再更新 \(f\) 和 \(g\) :
\[ g[i][j]=g[i][j]+f[i][j]∗f[k]\\ f[i][j]=f[i][j]+f[k]\\ g[i][j]=g[i][j]+f[k] \]
We must pay attention to the order.
However, such complexity is still \ (O (N ^ 2) \) the need to optimize the transfer.
Consider \ (I \) and \ (son [i] \) if \ (I \) only one son, then
\ [f [i] [j ] = f [i] [j-1], g [i] [j] = g [i] [j + 1] \]
Therefore, by moving the pointer \ (O (1) \) solution.
So we thought of a way to optimize: Each node can be extended up to inherit the son of answers by moving the pointer, the other son of violence calculations.
The complexity of the algorithm is:
\ [\ sum_ = {I}. 1 ^ n-DEP [I] - \ sum_ = {I}. 1 ^ NDEP [I] -1 = O (N) \]
Complexity is transferred up each son \ (DEP \) , since the depth of a node must be pointed to a long-chain son depth \ (1 + \) , it is possible to save \ (dep-1 \) transfer times.
code
The wording constant little, ah, Los Valley's first point \ (T \)
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=5e3+10;
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
ll ans;int g[maxn],d[maxn];
inline void dfs1(int x,int fa,int rt)
{
ans+=g[rt];
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (y==fa) continue;
dfs1(y,x,rt+1);
}
}
inline void dfs2(int x,int fa,int rt)
{
g[rt]+=d[rt];
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (y==fa) continue;
dfs2(y,x,rt+1);
}
}
inline void dfs3(int x,int fa,int rt)
{
++d[rt];
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (y==fa) continue;
dfs3(y,x,rt+1);
}
}
int main()
{
int n;read(n);
for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
for (int x=1; x<=n; ++x)
{
memset(d,0,sizeof(d));
memset(g,0,sizeof(g));
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
dfs1(y,x,1);
dfs2(y,x,1);
dfs3(y,x,1);
}
}
write(ans,'\n');
IO::flush();
return 0;
}
Writing look better, with the multiplication principle to statistics, the constant smaller
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=5e3+10;
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
template<typename T>inline bool chkMin(T &a,const T &b) { return a>b ? (a=b, true) : false; }
template<typename T>inline bool chkMax(T &a,const T &b) { return a<b ? (a=b, true) : false; }
int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
int dep[maxn],md,n;
ll g[maxn];
inline void dfs(int x,int fa)
{
chkMax(md,dep[x]);
++g[dep[x]];
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (y==fa) continue;
dep[y]=dep[x]+1;
dfs(y,x);
}
}
ll f1[maxn];//f1[j]表示以 i 号节点为根的子树中深度为选出一个深度为 j 的节点的方案数
ll f2[maxn];//f2[j]表示以 i 号节点为根的子树中深度为选出两个深度为 j 的节点的方案数
ll f3[maxn];//f3[j]表示以 i 号节点为根的子树中深度为选出三个深度为 j 的节点的方案数
inline ll query(int x)
{
ll sum=0;
memset(f1,0,sizeof(f1));
memset(f2,0,sizeof(f2));
memset(f3,0,sizeof(f3));
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
dep[y]=md=1;
dfs(y,x);
for (int j=md; j; --j) f3[j]+=f2[j]*g[j], f2[j]+=f1[j]*g[j], f1[j]+=g[j], g[j]=0;
}
for (int i=1; i<=n; ++i) sum+=f3[i];
return sum;
}
int main()
{
read(n); ll ans=0;
for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
for (int i=1; i<=n; ++i) ans+=query(i);
write(ans,'\n');
IO::flush();
return 0;
}
Enhanced version of the long-chain split coming
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=1e5+10;
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
int dep[maxn],son[maxn];
inline void dfs(int x,int fa)
{
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (y==fa) continue;
dfs(y,x);
if (dep[y]>dep[son[x]]) son[x]=y;
}
dep[x]=dep[son[x]]+1;
}
ll space[maxn*10],*now=space+maxn;
ll *f[maxn],*g[maxn], ans;
inline void create(int id)
{
f[id]=now, now+=dep[id]<<1|1;
g[id]=now, now+=dep[id]<<1|1;
}
inline 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 i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (y==fa || y==son[x]) continue;
create(y);
Dp(y,x);
for (int j=dep[y]; j>=0; --j)
{
if (j) ans+=f[x][j-1]*g[y][j];
ans+=g[x][j+1]*f[y][j];
g[x][j+1]+=f[x][j+1]*f[y][j];
}
for (int j=0; j<=dep[y]; ++j)
{
if (j) g[x][j-1]+=g[y][j];
f[x][j+1]+=f[y][j];
}
}
}
int main()
{
int n;read(n);
for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
dfs(1,0);
create(1);
Dp(1,0);
write(ans,'\n');
IO::flush();
return 0;
}