CF191C 树链剖分


点击打开链接

给出K个路径, 统计经过每条边的次数。

边的标记 与 下面的u一致


const  int  maxn = 100008 ;

int  n ;
int  siz[maxn] , top[maxn] , son[maxn] ;
int  dep[maxn] , tid[maxn] , fa[maxn] , rank[maxn]  ;
int  head[maxn] , to[maxn*2] , next[maxn*2] , edge ;
int  tim ;

void  init(){
      memset(head , -1 , sizeof(head)) ;
      memset(son , -1 , sizeof(son))  ;
      tim = edge = 0 ;
}

void  addedge(int u , int v){
      to[edge] = v , next[edge] = head[u] , head[u] = edge++ ;
      to[edge] = u , next[edge] = head[v] , head[v] = edge++ ;
}

void  dfs1(int u , int father , int d){
      dep[u] = d ;
      fa[u]  = father ;
      siz[u] = 1 ;
      for(int i = head[u] ; i != -1 ; i = next[i]){
            int v = to[i] ;
            if(v != father){
                 dfs1(v , u , d+1) ;
                 siz[u] += siz[v] ;
                 if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v ;
            }
      }
}

void  dfs2(int u , int tp){
      top[u] = tp ;
      tid[u] = ++tim ;
      rank[tid[u]] = u ;
      if(son[u] == -1) return  ;
      dfs2(son[u] , tp) ;
      for(int i = head[u] ; i != -1 ; i = next[i]){
           int v = to[i] ;
           if(v != son[u] && v != fa[u])  dfs2(v , v) ;
      }
}

int  c[maxn] ;

int  lowbit(int x){
     return x & (-x) ;
}

int  in(int i , int d){
     for( ; i <= n ; i += lowbit(i)) c[i] += d ;
}

int  gsum(int i){
     int t = 0 ;
     for( ; i >= 1 ; i -= lowbit(i)) t += c[i] ;
     return t  ;
}

struct  Line{
      int  u ,  v , id ;
}li[maxn]  ;

void  change(int x , int y){
      while(top[x] != top[y]){
           if(dep[top[x]] < dep[top[y]]) std::swap(x , y) ;
           in(tid[top[x]] , 1) ;
           in(tid[x] + 1 , -1) ;
           x = fa[top[x]] ;
      }
      if(x == y) return  ;
      if(dep[x] > dep[y]) std::swap(x , y) ;
      in(tid[x]+1 , 1) ;
      in(tid[y]+1 , -1) ;
}

int   main(){
      int i , j , u , v  , k  ;
      while(scanf("%d" , &n) != EOF){

           init() ;
           for(i = 1 ; i < n ; i++){
                scanf("%d%d" , &li[i].u , &li[i].v) ;
                li[i].id = i ;
                addedge(li[i].u , li[i].v) ;
           }

           dfs1(1 , 0 , 0) ;
           dfs2(1 , 1) ;

           for(i = 1 ; i < n ; i++){
                if(tid[li[i].u] < tid[li[i].v])
                    std::swap(li[i].u , li[i].v) ;
           }

           memset(c , 0 , sizeof(c)) ;
           scanf("%d" , &k) ;
           for(i = 1 ; i <= k ; i++){
                scanf("%d%d" , &u , &v) ;
                change(u , v) ;
           }
           for(i = 1 ; i < n ; i++)  printf("%d " , gsum(tid[li[i].u]))  ;
           puts("") ;

      }
      return  0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值