题面在这里

待我先膜拜一下楼教主……

首先这题是很明显的树分治
想说点什么却发现已经没什么好说了


然后我们来看另一种解法:平衡树乱搞
这里用的是Treap实现

对于每个节点,用Treap记录该子树每个节点到根(默认为1)的距离
那么如何统计答案?
对于兄弟子树,他们之中的任意节点间都可统计方案数,而且不会重复
其实统计方案数就是询问某Treap中key比x小的个数
统计两棵Treap之间的方案数就是把其中一棵树拆成一个一个点,不断询问
统计之后,将兄弟子树合并,得到了父亲子树的Treap
最后统计一棵子树的根到每个点是否能对答案做出贡献,并插入根节点
这里就要讲一下启发式合并,在合并过程中,如果我们每次都把较小的Treap拆成一个个点并插入另一个Treap中
就可以保证每个点最多被插入logNlogN次,那么复杂度就是Nlog2NNlog^2N(注意空间也要开NlogNNlogN)

示例程序:
树分治:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10005,maxe=2*maxn;
int n,k,hvy,S,ans;
int tot,lnk[maxn],nxt[maxe],son[maxe],w[maxe];
int siz[maxn],now[maxn],dep[maxn],MAX[maxn];
bool vis[maxn];
inline char nc(){static char buf[100000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int red(){int res=0,f=1;char ch=nc();while (ch<'0'||'9'<ch) {if (ch=='-') f=-f;ch=nc();}while ('0'<=ch&&ch<='9') res=res*10+ch-48,ch=nc();return res*f;
}
void add(int x,int y,int z){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;w[tot]=z;
}
void get_hvy(int x,int fa){siz[x]=1;MAX[x]=0;for (int j=lnk[x];j;j=nxt[j])if (son[j]!=fa&&!vis[son[j]]){get_hvy(son[j],x);siz[x]+=siz[son[j]];MAX[x]=max(MAX[x],siz[son[j]]);}MAX[x]=max(MAX[x],S-siz[x]);if (!hvy||MAX[x]<MAX[hvy]) hvy=x;
}
void get_dep(int x,int fa){now[++now[0]]=dep[x];for (int j=lnk[x];j;j=nxt[j])if (fa!=son[j]&&!vis[son[j]]){dep[son[j]]=dep[x]+w[j];get_dep(son[j],x);}
}
int get_sum(int x,int dst){now[0]=0;int res=0;dep[x]=dst;get_dep(x,0);sort(now+1,now+1+now[0]);for (int i=1,j=now[0];i<=now[0];i++){while (j>i&&now[i]+now[j]>k) j--;res+=max(0,j-i);}return res;
}
void get_ans(int x){vis[x]=1;ans+=get_sum(x,0);for (int j=lnk[x];j;j=nxt[j])if (!vis[son[j]]){ans-=get_sum(son[j],w[j]);hvy=0;S=siz[son[j]];get_hvy(son[j],0);get_ans(hvy);}
}
int main(){for (n=red(),k=red();n||k;n=red(),k=red()){memset(vis,0,sizeof(vis));memset(lnk,0,sizeof(lnk));tot=0;for (int i=1,x,y,z;i<n;i++)x=red(),y=red(),z=red(),add(x,y,z),add(y,x,z);hvy=0;S=n;get_hvy(1,0);ans=0;get_ans(hvy);printf("%d\n",ans);}return 0;
}

Treap:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10005,maxe=20005;
int n,K,ans;
int son[maxe],nxt[maxe],lnk[maxn],w[maxe],tot;
bool vis[maxn];
void add(int x,int y,int wi){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;w[tot]=wi;
}
inline int red(){int tot=0;char ch=getchar();while (ch<'0'||'9'<ch) ch=getchar();while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=getchar();return tot;
}
struct node{node* s[2];int size,k,cnt,f;void maintain() {size=s[0]->size+s[1]->size+cnt;}
}treap[132880],nil;
typedef node* P_node;
P_node null,len,rt[maxn];
void clear(){null=&nil;null->s[0]=null->s[1]=null;null->size=null->cnt=0;len=treap;
}
P_node newnode(int key,int num){len->k=key;len->s[0]=len->s[1]=null;len->cnt=len->size=num;len->f=rand();return len++;
}
void rot(P_node &x,int d){P_node k=x->s[d^1];x->s[d^1]=k->s[d];k->s[d]=x;x->maintain();k->maintain();x=k;
}
void ist(P_node &x,int key,int num){if (x==null) x=newnode(key,num);elseif (key==x->k) x->cnt+=num;else{int d=key>x->k;ist(x->s[d],key,num);if (x->s[d]->f > x->f) rot(x,d^1);}x->maintain();
}
void merge(P_node &a,P_node b){if (b==null) return;ist(a,b->k,b->cnt);merge(a,b->s[0]);merge(a,b->s[1]);
}
int Rank(P_node x,int key){if (x==null) return 0;if (key==x->k) return x->s[0]->size+x->cnt;if (key<x->k) return Rank(x->s[0],key);return Rank(x->s[1],key)+x->s[0]->size+x->cnt;
}
int asksum(P_node a,P_node b,int x){if (b==null) return 0;return b->cnt*Rank(a,x-b->k)+asksum(a,b->s[0],x)+asksum(a,b->s[1],x);
}
void dfs(int x,int dst){vis[x]=1;for (int j=lnk[x];j;j=nxt[j])if (!vis[son[j]]){dfs(son[j],dst+w[j]);if (rt[son[j]]->size > rt[x]->size) swap(rt[son[j]],rt[x]);ans+=asksum(rt[x],rt[son[j]],2*dst+K);merge(rt[x],rt[son[j]]);}ans+=Rank(rt[x],dst+K);ist(rt[x],dst,1);
}
int main(){freopen("test.in","r",stdin);freopen("test.out","w",stdout);n=red(),K=red();while (n){memset(lnk,0,sizeof(lnk));tot=0;clear();for (int i=1;i<=n;i++) rt[i]=null;for (int i=1,x,y,wi;i<n;i++) x=red(),y=red(),wi=red(),add(x,y,wi),add(y,x,wi);memset(vis,0,sizeof(vis));ans=0;dfs(1,0);printf("%d\n",ans);n=red(),K=red();}
}

【楼天城男人八题】【树分治|Treap+启发式合并】POJ1741 Tree相关推荐

  1. 多重背包java版本实现_楼天城男人八题——POJ1742 Coins

    题目链接 传说中楼教主的做男人不易八题之一,这题多重背包应该算最简单的一道了 我AC的时候Users (Solved) 有3945了. 关于背包问题可以看 dd_engi 大牛的01背包.完全背包和多 ...

  2. 楼天城男人八题之博弈

    woc绝世好题! 大佬博客https://www.cnblogs.com/dramstadt/p/3439725.html #include<cstdio> #include<cst ...

  3. nyoj-137 取石子(三) (博弈,楼教主真男人八题)

    取石子(三) 时间限制: 1000 ms  |  内存限制: 1000 KB 难度: 6 描述 小王喜欢与同事玩一些小游戏,今天他们选择了玩取石子. 游戏规则如下:共有N堆石子,已知每堆中石子的数量, ...

  4. poj 1737男人八题之一 orz ltc

    这是楼教主的男人八题之一.很高兴我能做八分之一的男人了. 题目大意:求有n个顶点的连通图有多少个. 解法: 1.  用总数减去不联通的图(网上说可以,我觉得时间悬) 2.    用动态规划(数学递推) ...

  5. 楼教主男人八题(第一题)

    楼天城,1986 年出生,高中毕业于杭州十四中. 2004 年保送进清华大学计算机系.2008年进入姚期智院士领导的清华大学理论计算机中心攻读博士. 2017年初,创办小马智行(pony.ai).楼天 ...

  6. 楼教主男人八题,告一段落

    各位老板好,我是自在飞花. 细心的老铁可能发现了我没有讲第七题. 这个是因为第七题太难了.倒不是代码实现有多么难,而是把思路讲明白很难. 这个题的正解是 Garsia-Wachs 算法,一种在已知键值 ...

  7. 动态图连通性(线段树分治+按秩合并并查集)

    在考场上遇到了这个的板子题,,,所以来学习了一下线段树分治 + 带撤销的并查集. 题目大意是这样的:有m个时刻,每个时刻有一个加边or撤销一条边的操作,保证操作合法,没有重边自环,每次操作后输出当前图 ...

  8. 2021牛客OI赛前集训营-树数树【树上启发式合并,堆】

    正题 题目链接:https://ac.nowcoder.com/acm/contest/20107/C 题目大意 给出nnn个点的一棵树,求一个最长的序列使得数字互不相同且相邻编号节点的都是祖孙关系. ...

  9. 楼天成 男人八题 多重背包问题O(VN)

    题意:n种硬币,每种有A[i]个,面值分别为C[i]求在[1,m]之间能组成多少种不同的面值. 解:装箱问题谁都会写,但我原来写的一直是三重循环,关键在于每种有A[i]个,从而将每种硬币又循环了A[i ...

最新文章

  1. 多地发钱鼓励生育,能刺激年轻人生娃吗
  2. CMD命令查看当前电脑安装.NET Core SDK的版本号
  3. ssh闲置一段时间自动登出问题的解决
  4. 软件工程课堂作业——寻找“水王”
  5. 一个人,开始变得优秀,就会渐渐地从这些圈子消失了
  6. php 网站数量,PHP给网站添加在线人数统计
  7. c语言数组中两元素交换,如可交换两个数组中的元素?
  8. 调整自己,必须调整自己了
  9. JavaEE系统架构师学习路线
  10. f-admin——基于Laravel框架开发的基础权限后台系统
  11. cboard企业版源码_数据可视化BI平台——CBoard的部署与使用(笔记整理)
  12. Excel基础(10)SUMIF函数
  13. 自定义IP在PCIE中使用
  14. Java不修改尺寸压缩图片
  15. 条令考试小程序辅助器_小程序条令考试 微信小程序条令考试答题器
  16. android studio找不到app moudle和project moudle
  17. 工作后的5种放松方法
  18. Pycharm 编辑器文本中间出现有一条分割线
  19. 视频格式转换器哪个好?怎样使用?
  20. (6)Artemis持久化策略

热门文章

  1. 中国500强企业 | 双胞胎集团携手契约锁共建电子签章系统
  2. jCore中文本地化工作札记 - 1
  3. matlab A律PCM编码原理框图,求大神,讲解A律PCM编码吖
  4. java编写桌球游戏素材小球图片_小球图片_小球模板_小球设计素材下载
  5. 数据结构入门:计算算法的平均时间复杂度
  6. 如何选择一款合适的仓库存管理软件
  7. 人脸识别门禁入主社区 新潮不代表不安全
  8. Linux安装Redis并且修改端口号,redis-6.2.2
  9. html隐藏电话中间几位,ios 手机号码隐藏中间4位为*号
  10. 如何将几张照片拼成一张?