poj1741 树上的分治

题意是说给了n个点的树n<=10000,问有多少个点对例如(a,b)他们的之间的距离小于等于k 采用树的分治做

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=20005;
int H[maxn],nx[maxn*2],to[maxn*2],numofE,dist[maxn*2];
void add(int u, int v, int d)
{
    numofE++;
    dist[numofE]=d,
    to[numofE]=v,
    nx[numofE]=H[u],
    H[u]=numofE;
}
void init(int N)
{
   numofE=0;
   memset(H,0,sizeof(H));
}
int ans;
bool center[maxn];
int subnum[maxn];
int Q[maxn+10],fa[maxn];
int searchroot(int cur)
{
     int rear=0,root=cur;
     Q[rear++]=cur;fa[cur]=0;
     for(int i=0; i<rear; i++){
         int x= Q[i];
         for(int j=H[x]; j; j=nx[j])
            if(to[j]!=fa[x]&& center[ to[j] ]==false)
              Q[rear++]=to[j],fa[to[j]]=x;
     }
     int MIN=100000000;
     for(int i=rear-1; i>=0; i--){

         int x=Q[i];
subnum[x]=1;
int MA=0;
         for(int j=H[x]; j ; j=nx[j])
            if(to[j]!=fa[x]&&center[ to[j] ]==false)
                MA=max(MA,subnum[to[j]]),subnum[x]+=subnum[to[j]];
         MA=max(MA,rear-subnum[ x ]);
         if(MIN>MA)MIN=MA,root=x;
     }
     return root;
}
int P[maxn];
int N,K;
int count_pair(int s, int t){
   int ge=0,R=t;
   for(int i=s; i<t; i++)
    {
        while(R>s&&P[R-1]+P[i]>K)R--;
        ge+=R-s-(R>i?1:0);
    }
   return ge/2;
}
void updateedg(int s, int cur, int d)
{
     int rear=0;
     Q[rear++]=cur; fa[cur]=0;P[s]=d;
     for(int i=0; i<rear; i++)
     {
         int x=Q[i];
         for(int j=H[x]; j; j=nx[j])
         {
             int tto=to[j];
             if(center[tto]||tto==fa[x])continue;
             P[s+rear]=P[s+i]+dist[j],Q[rear++]=tto,fa[tto]=x;
         }
     }
     sort(P+s,P+s+rear);
}
int dfs(int s,int cur,int d)
{
    int root,tot=1;
    root=searchroot(cur);
    center[root]=true;
    for(int i=H[root]; i ; i=nx[i])
    {
         int tto=to[i];
         if(center[tto])continue;
         int n=dfs(s+tot,tto,dist[i]);
         ans-=count_pair(s+tot,s+tot+n);
         tot+=n;
    }
    P[s]=0;
    sort(P+s,P+s+tot);
    ans+=count_pair(s,s+tot);
    center[root]=false;
    updateedg(s,cur,d);
    return tot;
}

int main()
{
    memset(center,false,sizeof(center));
    while(scanf("%d%d",&N,&K)==2)
        {
             if(!N&&!K)break;
              ans=0;
              init(N);
              for(int i=1; i<N; i++){
                int a,b,d;
                scanf("%d%d%d",&a,&b,&d);
                add(a,b,d);add(b,a,d);
              }
              dfs(0,1,0);
              printf("%d\n",ans);
        }
    return 0;
}
View Code

 

posted @ 2015-10-05 17:38  来自大山深处的菜鸟  阅读(209)  评论(0编辑  收藏  举报