标签:void can com bzoj while clu tin for 点分治
树的重心:删去这个点后,森林中所有树节点的最大值最小

#include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define maxn 10005 struct Edge{ int next,to,w; }edge[maxn*2]; int fi[maxn],se,n,k,size[maxn],root,ma[maxn],sum,ans,depth[maxn]; int b[maxn],si; bool vis[maxn]; inline void add_edge(int u,int v,int w){ edge[++se].next=fi[u],edge[se].to=v,edge[se].w=w,fi[u]=se, edge[++se].next=fi[v],edge[se].to=u,edge[se].w=w,fi[v]=se; } int cal(int x){ } void getroot(int x,int f){//找到当前树的重心 size[x]=1,ma[x]=0; for(int i=fi[x];i;i=edge[i].next){ int v=edge[i].to; if(v==f||vis[v])continue;//vis[v]=1表示不属于本棵树 getroot(v,x); size[x]+=size[v];ma[x]=max(ma[x],size[v]);//ma[x]为按x分开后最大子树的节点树 } ma[x]=max(ma[x],sum-size[x]);//sum-size[x]为父节点连接的子树的大小 if(ma[x]<ma[root])root=x;//更新重心 } void solve(int x){ ans+=cal(x);vis[x]=1;//先统计过重心的答案 for(int i=fi[x];i;i=edge[i].next){ int v=edge[i].to; if(vis[v])continue; sum=size[v];root=0; getroot(v,0);//递归找子树的重心 solve(root);//统计子树的答案 } } int main(){ sum = ma[0] = n;//初始化 root = 0; getroot(1,0);//找重心 solve(root);//点分治 return 0; }
POJ 1741 同BZOJ 1468(下面为POJ1741代码)
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 10005
struct Edge{
int next,to,w;
}edge[maxn*2];
int fi[maxn],se,n,k,size[maxn],root,ma[maxn],sum,ans,depth[maxn];
int b[maxn],si;
bool vis[maxn];
inline void add_edge(int u,int v,int w){
edge[++se].next=fi[u],edge[se].to=v,edge[se].w=w,fi[u]=se,
edge[++se].next=fi[v],edge[se].to=u,edge[se].w=w,fi[v]=se;
}
void getroot(int x,int f){//找到当前树的重心
size[x]=1,ma[x]=0;
for(int i=fi[x];i;i=edge[i].next){
int v=edge[i].to;
if(v==f||vis[v])continue;//vis[v]=1表示不属于本棵树
getroot(v,x);
size[x]+=size[v];ma[x]=max(ma[x],size[v]);//ma[x]为按x分开后最大子树的节点树
}
ma[x]=max(ma[x],sum-size[x]);//sum-size[x]为父节点连接的子树的大小
if(ma[x]<ma[root])root=x;//更新重心
}
void getdeep(int x,int f){
b[si++]=depth[x];
for(int i=fi[x];i;i=edge[i].next){
int v=edge[i].to;
if(v==f||vis[v])continue;
depth[v]=edge[i].w+depth[x];getdeep(v,x);
}
}
int cal(int x,int s){
depth[x]=s,si=0;
getdeep(x,0);
sort(b,b+si);
int l=0,r=si-1,ans=0;
while(l<r){
if(b[l]+b[r]<=k){
ans+=r-l;l++;
}
else r--;
}
return ans;
}
void solve(int x){
ans+=cal(x,0);vis[x]=1;//先统计过重心的答案
for(int i=fi[x];i;i=edge[i].next){
int v=edge[i].to;
if(vis[v])continue;
ans-=cal(v,edge[i].w);//本题在统计答案时有重复,这里去重
sum=size[v];root=0;
getroot(v,0);//递归找子树的重心
solve(root);//统计子树的答案
}
}
void work(){
int u,v,w;memset(fi,0,sizeof(fi)),memset(vis,0,sizeof(vis));
root=ans=se=0,sum=ma[0]=n;
for(int i=1;i<n;i++)scanf("%d%d%d",&u,&v,&w),add_edge(u,v,w);
getroot(1,0);
solve(root);
printf("%d\n",ans);
}
int main(){
while(~scanf("%d%d",&n,&k)&&n|k)work();
return 0;
}
标签:void can com bzoj while clu tin for 点分治
原文地址:https://www.cnblogs.com/bennettz/p/8902392.html