题意:
给出一个边上带权的无根树;
求距离不大于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