码迷,mamicode.com
首页 > 其他好文 > 详细

hdu5029 树链剖分 + 线段树

时间:2015-08-02 00:48:21      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:

  将树映射在线段上进行操作 然后每个 重链变成一个连续的区间
技术分享
#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
#include <algorithm>
#pragma comment(linker,"/STACk:10240000,10240000")
using namespace std;
const int maxn=100005;
vector<int>F[maxn];
int son[maxn],num[maxn],fa[maxn],top[maxn],p[maxn],fp[maxn],pos,depth[maxn],ans[maxn];
vector<int>P[maxn];
int loc,v;
struct SegmentItree{
    int num[maxn*4],id[maxn*4];
    void build(int o,int L, int R){
        num[o]=0;
        id[o]=0;
        if(L>=R){
             num[o]=0; id[o]=L;
             return ;
        }
        int mid = (L+R)/2;
        build(o*2,L,mid );
        build(o*2+1,mid+1,R);
    }
    void maintain(int o){
         num[o]=0;
         id[o]=0;
         if(num[o*2]==0&&num[o*2+1]==0)return;
         if( num[o*2] >= num[o*2+1] ){
            num[o]=num[o*2];
            id[o]=id[o*2];
         } else{
            num[o] =num[o*2+1];
            id[o]=id[o*2+1];
         }
    }
    void add(int o,int L, int R){
          if(L>=R){
             num[o]+=v;
            return ;
          }
          int mid = (L+R)>>1;
          if(loc<=mid){
             add(o*2,L,mid);
          }else{
             add(o*2+1, mid+1,R);
          }
          maintain(o);
    }
}T;
void inti(int n){
   for(int i=0; i<=n+2; ++i)
    F[i].clear(),P[i].clear();
    pos=0;
}
void dfs(int cur, int per,int dep){
    depth[cur]=dep;
    son[cur]=-1;
    fa[cur]=per;
    num[cur]=1;
    int Len= F[cur].size();
    for(int i=0; i<Len; ++i){
         int to = F[cur][i];
         if(to==per) continue;
         dfs(to,cur,dep+1); 
         num[cur]+=num[to];
         if( son[ cur ] == -1 || num[ son[cur] ]< num[to] ) son[cur]=to;
    }
}
void finde(int cur , int per, int xx){
      top[cur]=xx;
      pos++;
      p[cur]=pos;
      fp[pos]=cur;
      if(son[cur]!=-1)
      finde(son[cur],cur,xx);
      int len = F[cur].size();
      for(int i=0; i<len ;++i ){
           int to= F[cur][i];
           if(to==per||to==son[cur])continue;
           finde(to,cur,to);
      }
}
void solve(int x, int y,int d){
    int f1=top[x],f2=top[y];
    while(f1!=f2){
         if(depth[f1]<depth[f2]){
             int temp = x; x=y; y= temp;
             temp=f1; f1=f2; f2=temp;
         }
         P[ p[f1] ].push_back(d);
         P[ p[x]+1 ].push_back(-d);
         x=fa[f1];
         f1=top[x];
    }
    if(depth[x]>depth[y]){
        int temp = x; x = y ; y= temp;
    }
    P[p[x]].push_back(d);
    P[p[y]+1].push_back(-d);
}
int main()
{
    int n,m;
    for(;;){
        scanf("%d%d",&n,&m);
        if(n==0&&m==0)break;
        inti(n);
        for(int i=1; i<n ;++i ){
             int a,b;
             scanf("%d%d",&a,&b);
             F[a].push_back(b);
             F[b].push_back(a);
        }
        dfs(1,0,0);
        finde(1,0,1);
        int N=0;
        for(int i=0; i<m; ++i){
             int a,b,d;
             scanf("%d%d%d",&a,&b,&d);
             solve(a,b,d);
            N=max(d,N);
        }
       memset(ans,0,sizeof(ans));
       if(N!=0){
        T.build(1,1,N);
        for(int i=1; i<=n; ++i){
             int L = P[i].size();
             for(int j=0; j<L; ++j){
                 int to= P[i][j];
                 if(to>0){
                     v=1;
                     loc=to;
                 }else{
                     v=-1;
                     loc=-to;
                 }
                 T.add(1,1,N);
             }
             if(T.num[1]!=0)
             ans[fp[i]]=T.id[1];
             else ans[fp[i]]=0;
        }
       }
        for(int i=1; i<=n; ++i)
            printf("%d\n",ans[i]);
    }
    return 0;
}
View Code

 

hdu5029 树链剖分 + 线段树

标签:

原文地址:http://www.cnblogs.com/Opaser/p/3995401.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!