首先我们知道,这个题可以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. 守护线程以及要使用时注意的一点(Daemon Thread)

    在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) Daemon的作用是为其他线程的运行提供便利服务,比如垃圾回收线程就是一个很称职的守护者.User和 ...

  2. 教你配置使用阿里云 Maven 库,体验秒下 jar 包的快感

    鉴于国内的网络环境,从默认 Maven 库下载 jar 包是非常的痛苦. 速度慢就不说了,还经常是下不下来,然后一运行就是各种 ClassNotFoundException,然后你得找到残留文件删掉重 ...

  3. SQL中的逻辑运算符

    逻辑运算符和比较运算符一样,都是返回 true 或 false 值得布尔数据类型.   运算符 行为 ALL 如果一个比较集中全部都是 true ,则值为 true AND 如果两个布尔值表达式均为 ...

  4. 【Python】Python处理csv文件

    Python处理csv文件 CSV(Comma-Separated Values)即逗号分隔值,可以用Excel打开查看.由于是纯文本,任何编辑器也都可打开.与Excel文件不同,CSV文件中: 值没 ...

  5. HDU2460-Network

    题目 给一个\(n\)个点\(m\)条边的无向连通图,\(Q\)次往图中加边,每次加边后问图中的桥有多少个.(加边后边留着). \(n\le 10^5,m\le 2\times 10^5,Q\le 1 ...

  6. 【Linux】无法将 Ethernet0 连接到虚拟网络“VMnet8”

    Linux安装centos之后,可能会出现ipconfig命令之后没有看到eth0信息,只有lo.log日志包的错为:无法将 Ethernet0 连接到虚拟网络“VMnet8” 解决办法有: 1.在虚 ...

  7. vdbench测试过程中遇到的小问题

    1.报Slave hd2-0 prematurely terminated 错误 首先根据提示查看hd2-0.stdout.html文件获取更多的错误信息,这个问题一般是未安装vdbench或者路径不 ...

  8. 批量后台执行fio性能测试脚本

    安装ansible工具: )直接yum install -y ansible; )然后更改配置,/etc/ansible/ansible.cfg,将里面的host_key_checking = Fal ...

  9. C++ Win系统下的调试

    有的时候我们找不出错误在哪里,这时候我们需要调试一遍看看到底是哪里出了问题:我们需要分布查看程序运行情况. 这时候我们用到了调试这样一个神奇的东西. 一.基于Dev cpp环境下的调试 Dev cpp ...

  10. SNMP-网络管理协议

    SNMP协议简介: a. 轮询(Polling) -- 定时获取状态, 中断(Interrupt)--出问题通知 b. 共同体名(community) -- 口令--只读口令 --读写口令 使用SNM ...