首先我们知道,这个题可以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. ConcurrentHashMap原理分析(1.7与1.8)-put和 get 需要执行两次Hash

    ConcurrentHashMap 与HashMap和Hashtable 最大的不同在于:put和 get 两次Hash到达指定的HashEntry,第一次hash到达Segment,第二次到达Seg ...

  3. QT学习记录

    QApplication app(argc,argv); 创建了一个QApplication对象,这个对象用于管理应用程序级别的资源.QApplication的构造函数要求两个参数,分别来自main的 ...

  4. H Hip To Be Square Day5——NWERC2012

    这个题目巨坑啊.调试的时间加起来绝对超过1天整. 不过终于调试出来了,真心感动地尿流满面啊. 题目的意思是给你一个区间[A,B],可以从区间里选出任意多个整数,使得这些整数的积是一个不超过 2^126 ...

  5. 【JavaScript】JAVA-表格里的c:foreach使用及数字总计

    两步:1.上图 2.上代码 <div class="group-accordion" collapsible="true" active="tr ...

  6. MySQL二进制安装部署

    #使用二进制包安装mysql -linux-glibc2.-x86_64.tar.gz /data/ -linux-glibc2.-x86_64.tar.gz -C /data/ -linux-gli ...

  7. BZOJ5091 摘苹果(概率期望)

    大胆猜想每一步都相当于是第一步.稍微验证一下发现是对的.就做完了. #include<iostream> #include<cstdio> #include<cmath& ...

  8. 洛谷 P3924 康娜的线段树 解题报告

    P3924 康娜的线段树 题目描述 小林是个程序媛,不可避免地康娜对这种人类的"魔法"产生了浓厚的兴趣,于是小林开始教她\(OI\). 今天康娜学习了一种叫做线段树的神奇魔法,这种 ...

  9. 认识Java标识符

    标识符定义 认识Java标识符 在编程语言中,标识符就是程序员自己规定的具有特定含义的词,比如类名称,属性名称,变量名等. 问:标识符是神马? 答:标识符就是用于给 Java 程序中变量.类.方法等命 ...

  10. Codeforces 578.C Weakness and Poorness

    C. Weakness and Poorness time limit per test 2 seconds memory limit per test 256 megabytes input sta ...