蒟蒻的垂死挣扎
我好像有很久没有更博了。。。。不过觉得自己还是要记录一下的。
点分治支持在树上的询问操作,更多的是支持树上符合要求的路径的统计,形如 树上......的路径有多少 的问题一般就是点分治能解决的问题。
原理是每次处理出子树的重心,这样子树大小最少除以二,保证时间复杂度,然后强制统计经过重心的路径,保证程序的正确性。
这题可以说是模板题了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define MOD 998244353
#define N 40010
#define M 10001000
#define RG register
using namespace std;
inline int read(){
RG int x=0,o=1; RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1))+ch-'0',ch=getchar();
return x*o;
}
int n,Dis,top,first[N],dis[N],root,Max,Son,Siz,siz[N],vis[N],st[N],tot;
struct mona { int nxt,en; int w; } s[N<<1];
inline void Insert(int x,int y,int w) { s[++top]=(mona) { first[x],y,w },first[x]=top; }
inline void Getroot(int k,int fa){
siz[k]=1; int mmax=0;
for(RG int i=first[k];i;i=s[i].nxt){
int en=s[i].en; if(en==fa||vis[en]) continue ;
Getroot(en,k),siz[k]+=siz[en],mmax=max(mmax,siz[en]);
} mmax=max(mmax,Siz-siz[k]);
if(Max>mmax) Max=mmax,root=k;
}
inline void Getdis(int k,int fa,int w){
st[++tot]=w;
for(RG int i=first[k];i;i=s[i].nxt){
int en=s[i].en; if(en==fa||vis[en]) continue ;
Getdis(en,k,w+s[i].w);
} return ;
}
inline int Calc(int k,int ad){
tot=0,memset(st,0,sizeof(st)),Getdis(k,0,ad),sort(st+1,st+1+tot);
int le=1,ri=tot,ans=0;
while(le<=ri){
if(st[le]+st[ri]>Dis) --ri;
else ans+=ri-le,++le;
} return ans;
} int tans;
inline void Divide(int k){ //cout<<"Root "<<root<<endl;
tans+=Calc(k,0),vis[k]=1;
for(RG int i=first[k];i;i=s[i].nxt){
int en=s[i].en; if(vis[en]) continue ;
tans-=Calc(en,s[i].w);
// Siz= (siz[k] >= siz[en]) ? siz[en] : Siz - siz[k];
Siz=siz[en];
Max=1e9;
root=0,Getroot(en,0),Divide(root);
}
}
int main(){
n=read();
for(RG int i=1;i<n;++i){
int x=read(),y=read(),z=read();
Insert(x,y,z),Insert(y,x,z);
} Dis=read(),Max=1e9,Siz=n;
Getroot(1,0),Divide(root);
printf("%d\n",tans);
return 0;
}