link
樹上距離小於等於k點對對數
點分治模板
首先考慮經過某一點zx的對數,那麼我們可以通過dfs處理出所有點到zx的距離後求dis [a]+dis[b]<=k的個數(排序後雙指針),但是這樣算的時候還有可能兩點沒過zx,所以要容斥一下(減去所有以兒子節點爲根的數量即爲不經過zx的數量)。
如果隨便枚舉zx的話,最壞複雜度會達到O(n^2)
所以我們讓每次枚舉的點爲重心,複雜度爲O(nlog n) (每次都會減少大於s/2個節點)
#include<bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int maxn = 1e6 + 4;
const int N = 5e3 + 5;
const double eps = 1e-6;
const double pi = acos(-1.0);
ll qpow(ll x,ll y,ll mod){ll ans=1;x%=mod;while(y){ if(y&1) ans=ans*x%mod; x=x*x%mod; y>>=1;}return ans;}
//#define LOCAL
struct node{int v,w; };
int n,k,ans,zx,mn,tot,vis[maxn],sz[maxn],dis[maxn];
vector<node>G[maxn];
void dfs1(int u,int fa) {
sz[u]=1;
for(auto v:G[u]) if(v.v^fa&&!vis[v.v]) {
dfs1(v.v,u);sz[u]+=sz[v.v];
}
}
void dfs2(int u,int fa,int nn) {
int mx=nn-sz[u];
for(auto v:G[u]) if(v.v^fa&&!vis[v.v]) {
dfs2(v.v,u,nn);mx=max(mx,sz[v.v]);
}
if(mx<mn) mn=mx,zx=u;
}
void dfs3(int u,int fa,int d) {
dis[++tot]=d;
for(auto v:G[u]) if(v.v^fa&&!vis[v.v]) {
dfs3(v.v,u,d+v.w);
}
}
int kk(int u,int fa,int d) {
tot=0;dfs3(u,fa,d);
sort(dis+1,dis+tot+1);
int ans=0,i=1,j=tot;
while(i<j) {
if(dis[i]+dis[j]<=k) ans+=j-i,i++;
else j--;
}
return ans;
}
void dfs(int u ,int fa) {
mn=INT_MAX;
dfs1(u,fa);dfs2(u,fa,sz[u]);
vis[zx]=1;ans+=kk(zx,0,0);
int t=zx;
for(auto v:G[t]) if(v.v^fa&&!vis[v.v]){
ans-=kk(v.v,t,v.w);
dfs(v.v,t);
}
}
void init(int n) {
for(int i=0;i<=n;i++) G[i].clear(),vis[i]=0;
}
int main() {
#ifdef LOCAL
freopen("RACE input.in","r",stdin);
#endif
while(scanf("%d%d",&n,&k)&&n) {
init(n);
for(int i=1;i<n;i++) {
int u,v,w;scanf("%d%d%d",&u,&v,&w);
G[u].pb({v,w});G[v].pb({u,w});
}
ans=0;
dfs(1,0);
printf("%d\n",ans);
}
}