方法:指针扫描数组
每次选择树的重心作为树根,从树根出发进行一次DFS,求出点到树根的距离,把节点按照与树根的的距离放进数组d,设置两个指针L,R分别从前、后开始扫描,每次满足条件时答案累加R-L。,之后减去子树的满足条件的情况,删除根节点,对其子树继续上述操作,不断累加答案。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int maxn=100010; vector<pair<int,int> >G[maxn]; int d[maxn],size[maxn],root,max_w,n1,cnt,n,k; bool vis[maxn]; void get_root(int x,int f){//求树的重心 size[x]=1; int max_part=0; for(int i=0;i<G[x].size();i++){ int Next=G[x][i].first; if(Next!=f&&!vis[Next]){ get_root(Next,x); size[x]+=size[Next]; max_part=max(max_part,size[Next]); } } max_part=max(max_part,n1-size[x]); if(max_part<max_w){ root=x; max_w=max_part; } } void get_dist(int x,int f,int dist){//算距离 d[++cnt]=dist; size[x]=1;//算距离的同时也更新一下子树的大小 for(int i=0;i<G[x].size();i++){ int Next=G[x][i].first; if(Next!=f&&!vis[Next]){ get_dist(Next,x,dist+G[x][i].second); size[x]+=size[Next]; } } } int cal(int x,int y){//计算 cnt=0; get_dist(x,-1,y); sort(d+1,d+1+cnt); int ans=0; for(int i=1,j=cnt;i<j;i++){ while(d[i]+d[j]>k&&i<j)j--; ans+=j-i; } return ans; } int dfs(int x){//dfs主框架 max_w=n1; get_root(x,-1); int now=root; vis[now]=1; int ans=0; ans+=cal(now,0); for(int i=0;i<G[now].size();i++){ int Next=G[now][i].first; if(!vis[Next]){ ans-=cal(Next,G[now][i].second); n1=size[Next]; ans+=dfs(Next); } } return ans; } void init(int n){ for(int i=1;i<=n;i++)G[i].clear(); cnt=0; memset(vis,0,sizeof(vis)); } int main(){ int u,v,dis; while(~scanf("%d%d",&n,&k)&&n&&k){ init(n); for(int i=1;i<n;i++){ scanf("%d%d%d",&u,&v,&dis); G[u].push_back(make_pair(v,dis)); G[v].push_back(make_pair(u,dis)); } n1=n; printf("%d\n",dfs(1)); } } //5 1 //1 2 1 //2 3 1 //3 4 1 //4 5 1
原文地址:https://www.cnblogs.com/pkgunboat/p/9709941.html
时间: 2024-10-25 10:05:27