首先我们知道,这个题可以N^2的做,我们先确定一个根,然后讨论下情况,合法的三个点只可能有三种情况,第一种是三个点有相同的lca,这种情况我们可以用tree-dp来解决,用dis[i][j]表示i为根的子树中距离i为j的点的数量,然后我们枚举儿子,处理出dis_[i][j]表示i子树中选两个点距离i为j的点对儿数量,且在不同子树中(到i路径无重合)。那么枚举儿子的时候可以处理出这种情况的答案。

  还有一种情况为在i的子树中选2个不同子树中的点,也是就dis_[i][j],然后第三个点不在i的子树中,那么我们枚举每一个点,bfs出距离这个点距离为j的且不在i的子树中的点的数量为fuck_dis[i][j],那么ans+=dis_[i][j]*fuck_dis[i][j]。因为每个节点只会有一个父亲,所以最多只能向上引一条不重叠的链,保证了算法的正确性。

  反思:这道题不算特别难,但是写了挺长时间,开始的时候之想到了第一中情况,第二种情况只考虑了对于两个点距离i为j,i的一个祖先距离i为j,然后这个祖先可以成为答案,就用i的dep来判一下就好了。但是还有其他的可能,比如在某个地方拐一下,这个点到i的距离为j,所以我又写了每个点到除去子树中的点的距离最远的点,大于了j就可以更新答案,但是没有考虑到这个点有多种选法,所以最后写的距离i为j的点且不在i的子树中的数量,这个开始我想的是tree-dp,想了想觉得很不好写,总之tree-dp也是n^2,所以就写了每个点的bfs。

  备注:还有另外一种方法,其实我们第一种方法的本质就是讨论,我们可以发现所有满足条件的点对儿都可以通过选取不同的根来看成三个点有一个lca,那么我们可以枚举所有的点,然后bfs,每做一层我们都统计一下答案,方法和上一种方法的第一种情况类似,这种方法可以节省空间,但是觉得不是特别好写。

     这道题没有链的数据,我用dis[i][j]存的每个点的信息,但是n^2的内存会超,所以就估了一下不会超过2500左右,然后就把数组开小了些,其实应该用vector来存或者最开始选根的时候选重心来保证这个,但是懒得写了= =。

/**************************************************************
Problem: 3522
User: BLADEVIL
Language: C++
Result: Accepted
Time:2620 ms
Memory:118816 kb
****************************************************************/ //By BLADEVIL
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 5010
#define inf (~0U>>1) using namespace std; int n,l;
long long ans;
int pre[maxn<<],other[maxn<<],last[maxn];
int que[maxn],dep[maxn],dis[maxn][],dis_[maxn][],que_[maxn],dep_[maxn],father[maxn];
int jump[maxn][],fuck_dis[maxn][]; void connect(int x,int y) {
pre[++l]=last[x];;
other[l]=y;
last[x]=l;
} int main() {
//freopen("hot.in","r",stdin); freopen("hot.out","w",stdout);
scanf("%d",&n);
for (int i=;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
connect(x,y); connect(y,x);
}
int h=,t=; que[]=; dep[]=;
while (h<t) {
int cur=que[++h];
for (int p=last[cur];p;p=pre[p]) {
if (dep[other[p]]) continue;
que[++t]=other[p]; dep[other[p]]=dep[cur]+;
father[other[p]]=cur;
}
}
//for (int i=1;i<=n;i++) printf("%d ",standard[i]);
//for (int i=1;i<=n;i++) printf("%d ",que[i]);printf("\n");
for (int i=n;i;i--) {
int cur=que[i],sum=;
for (int p=last[cur];p;p=pre[p]) {
if (dep[other[p]]<dep[cur]) continue;
for (int j=;j<=dis[other[p]][];j++) ans+=dis_[cur][j+]*dis[other[p]][j];
ans+=dis_[cur][];
for (int j=;j<=dis[other[p]][];j++) dis_[cur][j+]+=dis[cur][j+]*dis[other[p]][j];
dis_[cur][]+=sum;
dis[cur][]=max(dis[cur][],dis[other[p]][]+);
for (int j=;j<=dis[other[p]][];j++) dis[cur][j+]+=dis[other[p]][j];
dis[cur][]++; sum++;
}
//printf("|%d %d\n",cur,dis[cur][1]);
//printf("||%d %d\n",cur,ans);
}
for (int i=;i<=n;i++) {
memset(dep_,,sizeof dep_);
memset(que_,,sizeof que_);
int h=,t=;
que_[]=father[i]; dep_[father[i]]=; dep_[i]=-;
while (h<t) {
int cur=que_[++h];
for (int p=last[cur];p;p=pre[p]) {
if ((dep_[other[p]])||(dep_[other[p]]==-)) continue;
que_[++t]=other[p]; dep_[other[p]]=dep_[cur]+;
}
}
for (int j=;j<=n;j++) fuck_dis[i][dep_[j]]++;
}
/*
for (int i=1;i<=n;i++) {
printf("%d ",i);
for (int j=1;j<=n;j++) if (fuck_dis[i][j]) printf("%d ",fuck_dis[i][j]);
printf("\n");
}
*/
for (int i=;i<=n;i++)
for (int j=;j<=dis[i][];j++) ans+=dis_[i][j]*fuck_dis[i][j];
printf("%lld\n",ans);
fclose(stdin); fclose(stdout);
return ;
}

bzoj 3522 tree-dp 暴力的更多相关文章

  1. bzoj 1017 tree dp

    这道题几经波折啊. 最开始和vfleaking一样,把题意理解错了,认为一个装备可能被多个装备依赖,然后想不出来,去看题解. 发现自己理解错了题意,自己想想,其实也不难想到dp[i][j][k]表示“ ...

  2. BZOJ 3522 DFS+DP

    思路: f[]表示选1个点的 g[]表示选2个点的 dp一下 ans+=(ll)g[k]*deep[k]; g[k]+=(ll)f[k]*deep[k]; f[k]+=deep[k]; 听说有O(n) ...

  3. bzoj 3522 / 4543 [POI 2014] Hotel - 动态规划 - 长链剖分

    题目传送门 bzoj 3522 需要root权限的传送点 bzoj 4543 快速的传送点 慢速的传送点 题目大意 给定一棵树,问有多少个无序三元组$(x, y, z)$使得这三个不同点在树上两两距离 ...

  4. bzoj 2212 Tree Rotations

    bzoj 2212 Tree Rotations 考虑一个子树 \(x\) 的左右儿子分别为 \(ls,rs\) .那么子树 \(x\) 内的逆序对数就是 \(ls\) 内的逆序对数,\(rs\) 内 ...

  5. 96. Unique Binary Search Trees (Tree; DP)

    Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For examp ...

  6. HDU 4359——Easy Tree DP?——————【dp+组合计数】

    Easy Tree DP? Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  7. TYOI Day1 travel:Tree dp【处理重复走边】

    题意: 给你一棵树,n个节点,每条边有长度. 然后有q组询问(u,k),每次问你:从节点u出发,走到某个节点的距离mod k的最大值. 题解: 对于无根树上的dp,一般都是先转成以1为根的有根树,然后 ...

  8. HDU 4359 Easy Tree DP?

    Easy Tree DP? Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  9. C. Ilya And The Tree 树形dp 暴力

    C. Ilya And The Tree 写法还是比较容易想到,但是这么暴力的写法不是那么的敢写. 就直接枚举了每一个点上面的点的所有的情况,对于这个点不放进去特判一下,然后排序去重提高效率. 注意d ...

  10. BZOJ.3522.[POI2014]Hotel(DP)

    题目链接 BZOJ 洛谷 以为裸点分治,但数据范围怎么这么小?快打完了发现不对.. n^2做的话其实是个水题.. 枚举每一个点为根,为了不重复计算,我们要求所求的三个点必须分别位于三棵子树上. 考虑当 ...

随机推荐

  1. docker+mesos+marathon

    前言 (Core) [root@docker-slave ~]# uname -r 3.10.0-229.4.2.el7.x86_64 [root@docker-slave ~]# uname -m ...

  2. 【刷题】BZOJ 4566 [Haoi2016]找相同字符

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别为 ...

  3. [AT2377] [agc014_e] Blue and Red Tree

    题目链接 AtCoder:https://agc014.contest.atcoder.jp/tasks/agc014_e 洛谷:https://www.luogu.org/problemnew/sh ...

  4. 洛谷 U14472 数据结构【比赛】 【差分数组 + 前缀和】

    题目描述 蒟蒻Edt把这个问题交给了你 ---- 一个精通数据结构的大犇,由于是第一题,这个题没那么难.. edt 现在对于题目进行了如下的简化: 最开始的数组每个元素都是0 给出nnn,optopt ...

  5. 洛谷 P4240 毒瘤之神的考验 解题报告

    P4240 毒瘤之神的考验 题目背景 \(\tt{Salamander}\)的家门口是一条长长的公路. 又是一年春天将至,\(\tt{Salamander}\)发现路边长出了一排毒瘤! \(\tt{S ...

  6. Zookeeper(一) zookeeper基础使用

    一.Zookeeper是什么 (安装的是3.4.7) ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现.它提供了简单原始的功能, ...

  7. C++11新利器

    C++11常用特性的使用经验总结 unordered_map可能用的会比较多 省的写哈希表了. 但是浪费空间

  8. get与post请求简单理解

    一般在浏览器中输入网址访问资源都是通过GET方式:在FORM提交中,可以通过Method指定提交方式为GET或者POST,默认为GET提交 Http定义了与服务器交互的不同方法,最基本的方法有4种,分 ...

  9. HDU 6194 后缀数组

    string string string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  10. H5禁止手机虚拟键盘弹出

    点击输入框弹出自定义弹窗,输入框是input标:但是在移动端,input会默认触发手机的虚拟键盘,如何阻止手机虚拟键盘弹起呢?目前我试过有两个方案,一个是给input添加readonly属性,另一个就 ...