【Luogu】P3565HOT-Hotels(树形DP)

  题目链接

  水了半个月之后Fd终于开始做题啦!

  然后成功的发现自己什么都不会了

  树形DP,既然是三个点两两距离相等那一定得有个中心点吧,枚举那个中心点,然后暴力DFS,根据乘法原理算。

  乘法原理就是我一个子树,距离为i的选择情况增加tot[i],两个子树的话是一个子树的选择情况乘上tot[i],三个子树(就是答案)就是两个子树的选择情况乘上tot[i];

  挺暴力的……不过貌似POI能过了

  据说有个加强版100000数据范围,要什么长链剖分……记一下以后来填坑

  

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#define maxn 5010
using namespace std;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int next,to;
}edge[maxn*2];
int head[maxn],num;
inline void add(int from,int to){
    edge[++num]=(Edge){head[from],to};
    head[from]=num;
}

int dis[maxn];
int one[maxn];
int two[maxn];
int tot[maxn];

void dfs(int x,int fa){
    tot[dis[x]]++;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa)    continue;
        dis[to]=dis[x]+1;
        dfs(to,x);
    }
    return;
}

long long ans;

int main(){
    int n=read();
    for(int i=1;i<n;++i){
        int x=read(),y=read();
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;++i){
        memset(one,0,sizeof(one));
        memset(two,0,sizeof(two));
        dis[i]=0;
        for(int j=head[i];j;j=edge[j].next){
            int to=edge[j].to;
            memset(tot,0,sizeof(tot));
            dis[to]=1;
            dfs(to,i);
            for(int k=1;k<=n;++k){
                ans+=1LL*two[k]*tot[k];
                two[k]+=tot[k]*one[k];
                one[k]+=tot[k];
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-01-24 21:11  Konoset  阅读(137)  评论(0编辑  收藏  举报