/**//* 题意:给出一棵树,统计距离≤K的点对 O(n^2)算法过不了 对root为根的子树,统计 a -> root -> b 的个数,然后再分治对每棵子树都这样统计, 就能得到答案了。 这里通过限制路径(一定经过root)去统计降低思维复杂度了 但有一个问题,就是a,b属于root同一个子树的话显然要去掉 用dist[]存点到根的距离,然后count()函数头尾指针线性求得*first+*last<=K的个数 ret+=两两子树组成*first+*last<=K的个数(其中会包括同一个子树的情况) 再ret-=同一个子树组成*first+*last<=K的个数
将递归与序列seq结合起来,对子树1-N的递归,也是对序列seq[1-N]的递归 所以存一下要递归的序列seq[] 由于要对很多棵子树进行递归,用一个队列存每次扩展到的子树序列的头尾指针 具体看代码 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std;
const int MAXN = 10005;
struct Node{int w,v,next;}nodes[MAXN*2];
int G[MAXN]; int Q[MAXN][2],front,tail; int dist[MAXN],seq[MAXN]; bool vi[MAXN]; int N,L,alloc,M; int best_size,center,len,ret;
void add(int u,int v,int w) { nodes[alloc].v=v,nodes[alloc].w=w; nodes[alloc].next=G[u];G[u]=alloc++; }
int count(int *first,int *last) { int ret = 0; sort(first,last--); while(first<last) { if(*first+*last<=L)ret+=last-first++;//last行,则last之前肯定也行,统计first+1到last的个数 else last--; } return ret; }
int centerOfGravity(int u,int p) { int max_sub = 0,size = 1; for(int son=G[u];son!=-1;son=nodes[son].next) { int v=nodes[son].v; if(v==p||!vi[v])continue; int t = centerOfGravity(v,u); size += t; if(t>max_sub)max_sub = t; } if(Q[front][1]-Q[front][0]-size>max_sub) max_sub = Q[front][1]-Q[front][0]-size; if(max_sub<best_size) { center = u; best_size = max_sub; } return size; } void find(int u,int p,int now_dist) { seq[len] = u; dist[len++] = now_dist; int last = len; for(int son=G[u];son!=-1;son=nodes[son].next) { int v = nodes[son].v,w=nodes[son].w; if(!vi[v]||v==p)continue; find(v,u,now_dist+w); if(p==-1){//为根时 Q[tail][0]=last,Q[tail][1]=len;//存扩展的子树,在seq[last,len) tail++; ret-=count(dist+last,dist+len); last = len; } } } int main() { while(scanf("%d%d",&N,&L),N){ memset(G+1,-1,sizeof(int)*N); alloc = 0; for(int i=1;i<N;i++) { int w,v,u; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } ret = 0; front=0;tail=1; for(int i=1;i<=N;i++)seq[i]=i; for(Q[front][0]=1,Q[front][1]=N+1;front!=tail;front++) { //if(Q[front][0]==Q[front][1])continue; for(int i=Q[front][0];i<Q[front][1];i++)vi[seq[i]]=1; best_size=N+1; centerOfGravity(seq[Q[front][0]],-1);//
len = Q[front][0]; find(center,-1,0); ret+=count(dist+Q[front][0],dist+Q[front][1]);
for(int i=Q[front][0];i<Q[front][1];i++)vi[seq[i]]=0; } printf("%d\n",ret); } return 0; }
POJ 1987 Distance Statistics 跟上题一样 POJ 2114 Boatherds 是统计距离==K的个数 修改一下count函数即可
int count(int *first,int *last) { int ret = 0; sort(first,last--); while(first<last) { if(*first+*last<L)first++; else if(*first+*last>L)last--; else { if(*first==*last) { ret+=(last-first)*(last-first+1)/2; break; } int *b=first,*e=last; while(*b==*first)b++; while(*e==*last)e--; ret+=(b-first)*(last-e); first=b; last=e; } } return ret; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|