[POI2014] HOT-Hotels
前言
长剖板题,但是我实在懒得讲了,就直接贴代码了。
代码下部有少量讲解。
题目
代码
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
int n;
LL Read()
{
LL x = 0,sg = 1; char c = getchar();
while(c > '9' || c < '0') {if(c == '-') sg = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = (x*10) + (c^48);c = getchar();}
return x * sg;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x,T y){return x < 0 ? -x : x;}
int head[MAXN],tot;
struct edge{
int v,nxt;
}e[MAXN<<1];
void Add_Edge(int u,int v){
e[++tot] = edge{v,head[u]};
head[u] = tot;
}
void Add_Double_Edge(int u,int v) {
Add_Edge(u,v);
Add_Edge(v,u);
}
int son[MAXN],len[MAXN];
void dfs1(int x,int fa){
for(int i = head[x],v; i ;i = e[i].nxt){
if((v = e[i].v) == fa) continue;
dfs1(v,x);
if(len[v] > len[son[x]]) son[x] = v;
}
len[x] = len[son[x]] + 1;
}
LL tmp[MAXN<<2],*f[MAXN],*g[MAXN],*ID = tmp,ans;
void dfs2(int x,int fa){
f[x][0] = 1;
if(!son[x]) return;
f[son[x]] = f[x]+1,g[son[x]] = g[x]-1,dfs2(son[x],x);
ans += g[x][0];
for(int i = head[x],v; i ;i = e[i].nxt){
if((v = e[i].v) == fa || v == son[x]) continue;
f[v] = ID; ID += len[v]<<1;
g[v] = ID; ID += len[v]<<1;
dfs2(v,x);
for(int j = 0;j < len[v];++ j) {
if(j) ans += f[x][j-1] * g[v][j];
ans += g[x][j+1] * f[v][j];
}
for(int j = 0;j < len[v];++ j){
g[x][j+1] += f[x][j+1] * f[v][j];
f[x][j+1] += f[v][j];
if(j) g[x][j-1] += g[v][j];
}
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read();
for(int i = 1;i < n;++ i) Add_Double_Edge(Read(),Read());
dfs1(1,0);
f[1] = ID; ID += len[1]<<1;
g[1] = ID; ID += len[1]<<1;
dfs2(1,0);
Put(ans,'\n');
return 0;
}
/*
淦,以前长剖竟然一直没学懂,指针都不会
f[x][i] 表示x子树内到x距离为i的点个数
g[x][i] 表示x子树内(u,v) 到 lca(u,v) 的距离为dis,lca(u,v)到 x的距离为 dis-i的点对个数
继承长儿子状态用指针,这个是基础知识...
*/