LTC男人八题系列
树的点分治裸题,同poj1741。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 40005 using namespace std; int n,k,sum,cnt,tot,mn,root,ans; int head[maxn],sz[maxn],mx[maxn],dis[maxn]; bool vst[maxn]; struct edge_type{int next,to,v;}e[maxn*2]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add_edge(int x,int y,int z) { e[++cnt]=(edge_type){head[x],y,z};head[x]=cnt; e[++cnt]=(edge_type){head[y],x,z};head[y]=cnt; } inline void getroot(int x,int fa) { sz[x]=1;mx[x]=0; for(int i=head[x];i;i=e[i].next) { int y=e[i].to; if (!vst[y]&&y!=fa) { getroot(y,x); sz[x]+=sz[y]; mx[x]=max(mx[x],sz[y]); } } mx[x]=max(mx[x],sum-sz[x]); if (mx[x]<mx[root]) root=x; } inline void dfs(int x,int d,int fa) { dis[++tot]=d; for(int i=head[x];i;i=e[i].next) { int y=e[i].to; if (y!=fa&&!vst[y]) dfs(y,d+e[i].v,x); } } inline int calc(int x,int d) { int ret=0; tot=0; dfs(x,d,0); sort(dis+1,dis+tot+1); int i=1,j=tot; while (i<j) { while (dis[i]+dis[j]>k&&i<j) j--; ret+=j-i; i++; }//左端点递增,右端点递减,巧妙的思路 return ret; } inline void solve(int x) { ans+=calc(x,0); vst[x]=true; for(int i=head[x];i;i=e[i].next) { int y=e[i].to; if (!vst[y]) { ans-=calc(y,e[i].v); root=0;sum=sz[y]; getroot(y,0); solve(root); } } } int main() { n=read(); F(i,1,n-1) { int x=read(),y=read(),z=read(); add_edge(x,y,z); } k=read(); mx[0]=sum=n;getroot(1,0); solve(root); printf("%d\n",ans); return 0; }