楼教主男人八题之一。
点分治看腻了吧。来点新鲜的。
关于启发式合并,我的上篇博客已经写了一些,请移步 这儿。
树的路径问题在这里可化为树上一对点的问题。
同样,每个叶节点建一个包含自己的平衡树。
dfs回溯时,非叶节点选取含点最多的子节点的平衡树作为自己的平衡树,将其他的子节点的平衡树暴力合并到这个树上。
同时查询这个子节点中小于给定要求长度的节点的个数,更新答案即可。
注意暴力合并时,要先询问再合并,否则本树上的节点会有重复计算。
由于每个节点的插入次数小于O(logn),总插入次数不超过O(nlogn)。
用treap进行插入、查询复杂度为O(logn),因此总复杂度为O(nlognlogn)。
不过不进行删除操作的话,需要O(nlogn)的空间。
实际效果不错,157ms。
点分治看腻了吧。来点新鲜的。
关于启发式合并,我的上篇博客已经写了一些,请移步 这儿。
树的路径问题在这里可化为树上一对点的问题。
同样,每个叶节点建一个包含自己的平衡树。
dfs回溯时,非叶节点选取含点最多的子节点的平衡树作为自己的平衡树,将其他的子节点的平衡树暴力合并到这个树上。
同时查询这个子节点中小于给定要求长度的节点的个数,更新答案即可。
注意暴力合并时,要先询问再合并,否则本树上的节点会有重复计算。
由于每个节点的插入次数小于O(logn),总插入次数不超过O(nlogn)。
用treap进行插入、查询复杂度为O(logn),因此总复杂度为O(nlognlogn)。
不过不进行删除操作的话,需要O(nlogn)的空间。
实际效果不错,157ms。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
#define NN 10100
int tn;
struct treap{
int l,r,fix,tot,val,cnt;
void init(int v){
l=r=0;
fix=rand()*rand();
tot=cnt=1;
val=v;
}
}t[NN*12];
void init_treap(){
srand(1314);
tn=0;
t[0].cnt=t[0].tot=0;
t[0].fix=-1000001000;
}
#define getot(p) \
do{\
t[p].tot=t[p].cnt;\
if (t[p].l) t[p].tot+=t[t[p].l].tot;\
if (t[p].r) t[p].tot+=t[t[p].r].tot;\
}while(0);
/*
inline void getot(int p){
t[p].tot=t[p].cnt;
if (t[p].l) t[p].tot+=t[t[p].l].tot;
if (t[p].r) t[p].tot+=t[t[p].r].tot;
}
*/
inline void rrot(int &p){
int y=t[p].l;
t[p].l=t[y].r;
t[y].r=p;
getot(p);
p=y;
getot(p);
}
inline void lrot(int &p){
int y=t[p].r;
t[p].r=t[y].l;
t[y].l=p;
getot(p);
p=y;
getot(p);
}
void insert(int val,int &p,int num=1){
if (p==0) {
p=++tn;
t[p].init(val);
t[p].cnt=t[p].tot=num;
return;
}
t[p].tot+=num;
if (val==t[p].val) {t[p].cnt+=num;}
else if (val<t[p].val){
insert(val,t[p].l,num);
if (t[p].fix>t[t[p].l].fix) rrot(p);
}
else {
insert(val,t[p].r,num);
if (t[p].fix>t[t[p].r].fix) lrot(p);
}
//getot(p);
}
int queryless(int val,int p){
if (val==t[p].val) return t[t[p].l].tot+t[p].cnt;
else if (val<t[p].val){
if (t[p].l) return queryless(val,t[p].l);
else return 0;
}
else {
if (t[p].r) return t[t[p].l].tot+t[p].cnt+queryless(val,t[p].r);
else return t[t[p].l].tot+t[p].cnt;
}
}
int fi[NN],ne[NN*2],to[NN*2],w[NN*2],te;
void addedge(int fr,int t,int val){
ne[te]=fi[fr];fi[fr]=te;to[te]=t;w[te++]=val;
}
int n,k;
int ans;
int son[NN],tot[NN],root[NN];
int dis[NN],sw[NN];
void dfs1(int u,int fa){
son[u]=-1;
tot[u]=1;
int ma=-1,e,v;
for(e=fi[u];e!=-1;e=ne[e]){
v=to[e];
if (v!=fa){
dfs1(v,u);
if (tot[v]>ma) {ma=tot[v];son[u]=v;sw[u]=w[e];}
tot[u]+=tot[v];
}
}
}
void merge(int &ru,int rv,int du,int dv){
insert(t[rv].val+dv-du,ru,t[rv].cnt);
if (t[rv].l) merge(ru,t[rv].l,du,dv);
if (t[rv].r) merge(ru,t[rv].r,du,dv);
}
void query(int &ru,int rv,int du,int dv){
int tmp,val;
val=k-t[rv].val-du-dv;
tmp=queryless(val,ru);
ans+=tmp*t[rv].cnt;
if (t[rv].l) query(ru,t[rv].l,du,dv);
if (t[rv].r) query(ru,t[rv].r,du,dv);
}
void dfs2(int u,int fa,int dd){
int e,v;
if (son[u]==-1){
root[u]=++tn;t[tn].init(0);
dis[u]=dd;
return;
}
dfs2(son[u],u,sw[u]);
root[u]=root[son[u]];
dis[u]=dis[son[u]];
ans+=queryless(k-dis[u],root[u]);
insert(-dis[u],root[u],1);
for(e=fi[u];e!=-1;e=ne[e]){
v=to[e];
if (v!=fa&&v!=son[u]){
dfs2(v,u,w[e]);
query(root[u],root[v],dis[u],dis[v]);
merge(root[u],root[v],dis[u],dis[v]);
}
}
dis[u]+=dd;
}
int main(){
//freopen("1741in.txt","r",stdin);
int a,b,c,i;
while(scanf("%d%d",&n,&k)&&(n||k)){
te=0;
memset(fi,-1,sizeof(fi));
for(i=1;i<n;++i){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
init_treap();
dfs1(1,-1);
ans=0;
dfs2(1,-1,0);
printf("%d\n",ans);
}
return 0;
}