题意:
给出一个边上带权的无根树;
求距离不大于m的结点对数;
多组数据,n<=10000;
题解:
1/8个男人留念吧。。
学了树的分治之后来切这道题,听别人讲完写写就A了;
但是发现自己模板写的好烂,改了一大通;
这题就是考虑点分治,每次在当前子树中找经过重心的点对数;
那么就是将以重心为根的距离dis数组排序,然后双指针乱扫线性找出结点对数;
但是这里可能会出现在同一子树中的情况,每个子树也做一遍减掉就可以了;
然后我在每次子树的dis数组合并的时候搞了个归并。。实测并没有全弄完之后sort好;
分治时处理每颗当前树复杂度是O(size*log size),最坏logn层,复杂度为O(nlog^2n);
我的代码跑的并不快。。329ms我尽力了。。。;
代码:
#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 11000
using namespace std;
vector<int>to[N],val[N];
int size[N],dis[N],temp[N],mi,root,bk,m,ans,cnt;
bool ban[N];
void init(int n)
{
for(int i=1;i<=n;i++)
to[i].clear(),val[i].clear();
memset(ban,0,sizeof(ban));
ans=0;
}
void get_G(int x,int pre)
{
size[x]=1;
int i,y,temp=0;
for(i=0;i<to[x].size();i++)
{
if(!ban[y=to[x][i]]&&y!=pre)
{
get_G(y,x);
size[x]+=size[y];
temp=max(temp,size[y]);
}
}
temp=max(temp,bk-temp);
if(temp<mi)
mi=temp,root=x;
}
void dfs(int x,int pre,int d)
{
dis[++cnt]=d,size[x]=1;
int i,y;
for(i=0;i<to[x].size();i++)
{
if(!ban[y=to[x][i]]&&y!=pre)
{
dfs(y,x,d+val[x][i]);
size[x]+=size[y];
}
}
}
void merge(int mid)
{
int l=1,r=cnt,i,j,k;
memcpy(temp+1,dis+1,sizeof(int)*cnt);
for(i=l,j=l,k=mid+1;i<=r;i++)
{
if(j<=mid&&k<=r)
dis[i]=temp[j]<temp[k]?temp[j++]:temp[k++];
else
dis[i]=(j==mid+1?temp[k++]:temp[j++]);
}
}
int calc(int x)
{
int i,j,k,y,st,ret=0;
dis[cnt=1]=0;
for(i=0;i<to[x].size();i++)
{
if(!ban[y=to[x][i]])
{
st=cnt+1;
dfs(y,x,val[x][i]);
sort(dis+st,dis+cnt+1);
for(j=st,k=cnt;j<=cnt&&j<=k;j++)
{
while(dis[j]+dis[k]>m&&j<k)
k--;
ret+=k-j;
}
// merge(st-1); //归并函数
}
}
ret=-ret;
sort(dis+1,dis+cnt+1); //直接排序
for(j=1,k=cnt;j<=cnt&&j<=k;j++)
{
while(dis[j]+dis[k]>m&&j<k)
k--;
ret+=k-j;
}
return ret;
}
void slove(int x)
{
ban[x]=1;
ans+=calc(x);
int i,y;
for(i=0;i<to[x].size();i++)
{
if(!ban[y=to[x][i]])
{
mi=0x3f3f3f3f,bk=size[y];
get_G(y,x);
slove(root);
}
}
}
int main()
{
int n,i,j,k,x,y,v;
while(scanf("%d%d",&n,&m)&&(n||m))
{
init(n);
for(i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&v);
to[x].push_back(y),val[x].push_back(v);
to[y].push_back(x),val[y].push_back(v);
}
mi=0x3f3f3f3f,bk=n;
get_G(1,0);
slove(root);
printf("%d\n",ans);
}
return 0;
}
原文地址:http://blog.csdn.net/ww140142/article/details/46998089