【树链剖分模板】题

来源:互联网 发布:淘宝男士皮鞋哪家好 编辑:程序博客网 时间:2024/06/02 02:10

一、SPOJ375——Query on a tree (对边进行操作)

给一棵树 , N个点
两种操作:
1.i-ti :把第i条边的边权修改成ti
2.a-b :询问a到b路径上的边权最大值。

#include <bits/stdc++.h>using namespace std; /* */  const int MAXN = 20010;  struct Edge  {      int to,next;  }edge[MAXN*2];  int head[MAXN],tot;  int top[MAXN];//top[v]表示v所在的重链的顶端节点  int fa[MAXN]; //父亲节点  int deep[MAXN];//深度  int num[MAXN];//num[v]表示以v为根的子树的节点数  int p[MAXN];//p[v]表示v与其父亲节点的连边在线段树中的位置  int fp[MAXN];//和p数组相反  即 记录线段树中的某个位置的边的起点?int son[MAXN];//重儿子  int pos;   // 每条边在线段树中的位置。int n;  void init()  {      tot = 0;      memset(head,-1,sizeof(head));      pos = 1;//边的序号其实是从1开始?      memset(son,-1,sizeof(son));  }  void addedge(int u,int v)  {      edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;  }  void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son  {      deep[u] = d;      fa[u] = pre;      num[u] = 1;      for(int i = head[u];i != -1; i = edge[i].next)      {          int v = edge[i].to;          //因为路径是双向的,所以不能等于父节点        if(v == pre)  continue;           dfs1(v,u,d+1);          //更新u节点的儿子数目          num[u] += num[v];          if(son[u] == -1 || num[v] > num[son[u]])//求出重儿子即:所有儿子中size 最大的节点v                son[u] = v;      }  }  //因为对于轻儿子来说,top[u]=u,对于重儿子来说,如果son[v]!=-1,那么top[v]=top[son[v]]  void getpos(int u,int sp) //第二遍dfs求出top和p  {      top[u] = sp;      //先找重儿子      if(son[u] != -1)   // 存在重儿子    {          //把边的位置标记一下          p[u] = pos++;          //fp相当于是p的反函数,即记录线段树中某个位置的边 的在树中的起点。        fp[p[u]] = u;          //更新重儿子          getpos(son[u],sp);      }      //如果到了叶子节点      else      {          //不再向下dfs          p[u] = pos++;          fp[p[u]] = u;          return;      }      //更新其他的节点      for(int i = head[u] ; i != -1; i = edge[i].next)      {          int v = edge[i].to;          if(v != son[u] && v != fa[u])              getpos(v,v);   //  轻儿子的top[u]=u    }  }  #define lson l,m,rt<<1  #define rson m+1,r,rt<<1|1  int MAX[MAXN<<2];  int val[MAXN<<2];  void pushup(int rt){      MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);  }  void build(int l,int r,int rt){      if(l==r){          MAX[rt]=val[l];          return;      }      int m=(l+r)>>1;      build(lson);      build(rson);      pushup(rt);  }  void update(int p,int x,int l,int r,int rt){  // 单点更新    if(l==r){          MAX[rt]=x;          return;      }      int m=(l+r)>>1;      if(p<=m)          update(p,x,lson);      else          update(p,x,rson);      pushup(rt);  }  int query(int L,int R,int l,int r,int rt){    // 区间询问    if( L<=l &&r<=R){          return MAX[rt];      }      int m=(l+r)>>1;      int res=0;      if(m>=L)          res=max(res,query(L,R,lson));      if(R>m)          res=max(res,query(L,R,rson));      return res;  }  int _find(int u,int v){   // 找 a-----b 中所有路径的最大值。    int f1=top[u],f2=top[v];//先找到两个端点的重链顶端节点,如果是轻儿子,就是它本身      int temp=0;      while(f1!=f2){          //从深度较深的开始查询          if(deep[f1]<deep[f2]){              swap(f1,f2);              swap(u,v);          }          //查询一条重链上的最大值          temp=max(temp,query(p[f1],p[u],1,n,1));          u=fa[f1];f1=top[u];      }      //如果f1=f2代表在同一条重链上m,如果u=v代表更新结束      if(u==v)          return temp;      if(deep[u]>deep[v])          swap(u,v);      return max(temp,query(p[son[u]],p[v],1,n,1));  }  int e[MAXN][3];  int main(){      int t;      freopen("1.txt","r",stdin);    scanf("%d",&t);      while(t--){          init();          scanf("%d",&n);          getchar();          for(int i=0;i<n-1;i++){              scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);              addedge(e[i][0],e[i][1]);              addedge(e[i][1],e[i][0]);          }          dfs1(1,0,0);          getpos(1,1);            // 现在已经把树剖分完毕。        for(int i=0;i<n-1;i++){                if(deep[e[i][0]]<deep[e[i][1]])    // 调整每条路径的父亲,儿子关系。0>1 0为儿子1为父亲                swap(e[i][0],e[i][1]);              val[ p[e[i][0]] ]=e[i][2];   //  pi表示i和其父亲连边在线段树中的位置。        }          build(1,n,1);   // 以val建树        char op[10];          int u,v;          while(scanf("%s",op)){              if(op[0]=='D') break;              scanf("%d%d",&u,&v);              if(op[0]=='Q')                  printf("%d\n",_find(u,v));              else                  update(p[e[u-1][0]],v,1,n,1);          }      }      return 0;  }  

这是模板,可以发现,这个数据结构和大多数事物一样,揭开这一层神秘的面纱之后也就那么一回事。最关键的还是思维,这个很重要。

二、hdu3966(对点进行操作)

题意:给一棵树N个点,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值

这个题只对点进行操作,那么我们线段树里面放点,
现在的问题是需要对某条路径上所有的点(所有的路径其实也同理)进行操作,那么该如何?
首先我们在线段树中是按重链在前,轻链在后 有顺序的放进去的(pos)
那么我们肯定也可以在线段树中区间更新(和边是同理)

例如要更新[l,r]
那么首先找到 top[l] top[r] 如果top相等 那么表示他们在一条重链上,此时其点(边)在线段树中都是连续的
如果不等,那么 我们选择deep较深的那个节点向较深的节点靠近,我们假设L为那个更深的节点. 更新(L, top[L]) 然后让L=top[L] ,

然后我们可以发现重复此过程可以把所有的点(或边更新完) 最多不会超过logn次

const int MAXN = 50010;  struct Edge  {      int to,next;  }edge[MAXN*2];  int head[MAXN],tot;  int top[MAXN];//top[v]表示v所在的重链的顶端节点  int fa[MAXN]; //父亲节点  int deep[MAXN];//深度  int num[MAXN];//num[v]表示以v为根的子树的节点数  int p[MAXN];//p[v]表示点 在线段树中的位置  int fp[MAXN];//和p数组相反  即 记录线段树中的某个位置 存的是那个点int son[MAXN];//重儿子  int pos;   // 每个点在线段树中的位置。int n;    int  a[MAXN];  int b[MAXN];void init()  {      tot = 0;      memset(head,-1,sizeof(head));      pos = 1;//边的序号其实是从1开始?      memset(son,-1,sizeof(son));  }  void addedge(int u,int v)  {      edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;  }  void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son  {      deep[u] = d;      fa[u] = pre;      num[u] = 1;      for(int i = head[u];i != -1; i = edge[i].next)      {          int v = edge[i].to;          //因为路径是双向的,所以不能等于父节点        if(v == pre)  continue;           dfs1(v,u,d+1);          //更新u节点的儿子数目          num[u] += num[v];          if(son[u] == -1 || num[v] > num[son[u]])//求出重儿子即:所有儿子中size 最大的节点v                son[u] = v;      }  }  //因为对于轻儿子来说,top[u]=u,对于重儿子来说,如果son[v]!=-1,那么top[v]=top[son[v]]  void getpos(int u,int sp) //第二遍dfs求出top和p  {      top[u] = sp;      //先找重儿子      if(son[u] != -1)   // 存在重儿子    {          //把点的位置标记一下          p[u] = pos++;           b[ p[u] ] = a[u];  // 原始点  u 的值为a[u] , u在线段树中的位置为p[u] ,那么        fp[p[u]] = u;          //更新重儿子          getpos(son[u],sp);      }      //如果到了叶子节点      else      {          //不再向下dfs          p[u] = pos++;          b[ p[u] ] = a[u];        fp[p[u]] = u;          return;      }      //更新其他的节点      for(int i = head[u] ; i != -1; i = edge[i].next)      {          int v = edge[i].to;          if(v != son[u] && v != fa[u])              getpos(v,v);   //  轻儿子的top[u]=u    }  }  #define lson l,m,rt<<1  #define rson m+1,r,rt<<1|1   struct seg{    int l,r;    int lazy;    int v;}st[MAXN<<2];void push_down(int rt){  // 这个pushdown 每次都写得很艰难啊  , 这样写的话 需要放在每一次更新和询问的第一行。    if(st[rt].lazy!=0  ){        // printf("pushdown :%d,%d ------%d\n",st[rt].l,st[rt].r, st[rt].lazy );        st[rt].v+=st[rt].lazy;        if(st[rt].l!=st[rt].r){             st[rt<<1].lazy+=st[rt].lazy;            st[rt<<1|1].lazy+=st[rt].lazy;         }        st[rt].lazy=0;    }}void build(int l,int r,int rt){      st[rt].lazy=st[rt].v=0;    st[rt].l=l;    st[rt].r=r;        if(l==r){              st[rt].v=b[l];            return;        }         int m=(l+r)>>1;        build(lson);        build(rson);   }  void update(int v,int L,int R,int l,int r,int rt){  // 区间更新         push_down(rt);       if( L<=l &&r<=R){             // printf("up :%d %d %d\n",st[rt].l,st[rt].r ,v);                        st[rt].lazy+=v;            return;           }           int m=(l+r)>>1;           if(m>=L)              update(v,L,R,lson);      if(R>m)                    update(v,L,R,rson);   }  int query(int p,int l,int r,int rt){    // 单点询问     push_down(rt);    if( l==r && l==p){          return st[rt].v;      }      // printf("qur:%d %d %d    p=%d   push%d\n",l,r,rt,p ,st[rt].lazy);    int m=(l+r)>>1;       if(p<=m)          return query(p,lson);    else        return query(p,rson); }  void _find(int u,int v,int k){        int f1=top[u],f2=top[v];//先找到两个端点的重链顶端节点,如果是轻儿子,就是它本身      int temp=0;      while(f1!=f2){          //从深度较深的开始查询          if(deep[f1]<deep[f2]){              swap(f1,f2);              swap(u,v);          }          //查区间改变        update(k,p[f1],p[u],1,n,1);   //  u----top[u]    在dfs的时候显然top先放入线段树        u=fa[f1];f1=top[u];      }      //如果f1=f2代表在同一条重链上m,如果u=v 那么也需要单点更新    // if(u==v)      //     return ;    if(deep[u]>deep[v])          swap(u,v);       update(k,p[u],p[v],1,n,1) ;   // v-----u  deep[u]小 那自然先放入线段树}  char op[5];int main(){      int t;      freopen("1.txt","r",stdin);    int q,m;     while(~scanf("%d %d %d",&n,&m,&q) ){         init();          for(int i=1;i<=n;i++)            scanf("%d",&a[i]);          int u,v;          for(int i=1;i<n;i++){            scanf("%d %d",&u,&v);            addedge(u,v);            addedge(v,u);          }          dfs1(1,0,1);          getpos(1,1);          build(1,n,1);          int  k;          while(q--){            scanf("%s",op);            if(op[0]=='I'){ //+                scanf("%d %d %d",&u,&v,&k);                _find(u,v,k);            }            else if(op[0]=='D'){  // -            scanf("%d %d %d",&u,&v,&k);                _find(u,v,-1*k);            }            else{                scanf("%d",&u);                printf("%d\n",query(p[u],1,n,1));            }             // printf("\n\nq=%d\n",q);            //  for(int i=1;i<=n;i++){            //  printf("i=%d  p=%d %d\n",i,p[i],query(p[i],1,n,1));              // }          }     }    return 0;  }  

wa一次是因为在_find里面 如果 u==v那么不会进行更新,我们也应该对其进行单点更新。顺便有更新了一波线段树push_down写法,(滑稽

3.BZOJ1036: [ZJOI2008]树的统计Count (对点进行操作)

也是裸的树链剖分,不过注意以下几个点:
1.有可能是负数,所以取maxx的时候ans初始值为很大的负数,不能为0
2.进行单点更新是 , 很容易写成更新u , 应该是更新p[u]
3.顺便记得 init ,先输入数组,在dfs,getpos ,build 等等
wa+2

const int MAXN = 30010;  struct Edge  {      int to,next;  }edge[MAXN*2];  int head[MAXN],tot;  int top[MAXN];//top[v]表示v所在的重链的顶端节点  int fa[MAXN]; //父亲节点  int deep[MAXN];//深度  int num[MAXN];//num[v]表示以v为根的子树的节点数  int p[MAXN];//p[v]表示点 在线段树中的位置  int fp[MAXN];//和p数组相反  即 记录线段树中的某个位置 存的是那个点int son[MAXN];//重儿子  int pos;   // 每个点在线段树中的位置。int n;    // 记得 n一定要开全局  int  a[MAXN];  // 原始点  u 的值为a[u] , u在线段树中的位置为p[u]    int b[MAXN];   // 线段树  b[ p[u] ]=a[u];void init()  {      tot = 0;      memset(head,-1,sizeof(head));      pos = 1;//边的序号其实是从1开始?      memset(son,-1,sizeof(son));  }  void addedge(int u,int v)  {      edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;  }  void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son  {      deep[u] = d;      fa[u] = pre;      num[u] = 1;      for(int i = head[u];i != -1; i = edge[i].next)      {          int v = edge[i].to;          //因为路径是双向的,所以不能等于父节点        if(v == pre)  continue;           dfs1(v,u,d+1);          //更新u节点的儿子数目          num[u] += num[v];          if(son[u] == -1 || num[v] > num[son[u]])//求出重儿子即:所有儿子中size 最大的节点v                son[u] = v;      }  }  //因为对于轻儿子来说,top[u]=u,对于重儿子来说,如果son[v]!=-1,那么top[v]=top[son[v]]  void getpos(int u,int sp) //第二遍dfs求出top和p  {      top[u] = sp;      //先找重儿子      if(son[u] != -1)   // 存在重儿子    {          //把点的位置标记一下          p[u] = pos++;           b[ p[u] ] = a[u];  // 原始点  u 的值为a[u] , u在线段树中的位置为p[u] ,那么        fp[p[u]] = u;          //更新重儿子          getpos(son[u],sp);      }      //如果到了叶子节点      else      {          //不再向下dfs          p[u] = pos++;          b[ p[u] ] = a[u];        fp[p[u]] = u;          return;      }      //更新其他的节点      for(int i = head[u] ; i != -1; i = edge[i].next)      {          int v = edge[i].to;          if(v != son[u] && v != fa[u])              getpos(v,v);   //  轻儿子的top[u]=u    }  }  #define lson l,m,rt<<1  #define rson m+1,r,rt<<1|1   struct seg{    int l,r;     int v;    int maxx;  // 最大值    int sum;   // 权值之和}st[MAXN<<2];void push_up(int rt){    st[rt].maxx= max(st[rt<<1].maxx,st[rt<<1|1].maxx) ;    st[rt].sum=st[rt<<1].sum  + st[rt<<1|1].sum  ;}void build(int l,int r,int rt){       st[rt].l=l;    st[rt].r=r;    st[rt].maxx=st[rt].v=0;        if(l==r){              st[rt].v=st[rt].maxx=st[rt].sum=b[l];            // printf("l=%d  %d\n",l,b[l]);            return;        }         int m=(l+r)>>1;        build(lson);        build(rson);         push_up(rt);}  void update(int p, int v,int l,int r,int rt){  //  单点       if( l==r ){             // printf("up :%d %d %d\n",st[rt].l,st[rt].r ,v);                        st[rt].v=v;                        st[rt].sum=v;                        st[rt].maxx=v;            return;           }           int m=(l+r)>>1;           if(p<=m)                    update(p,v,lson);          else                   update(p,v,rson);              push_up(rt);}  int query(int L,int  R,int l,int r,int rt,int k){    //  区间     if(  L <=l && r<=R){          // printf("qur:%d %d===%d  %d\n",st[rt].l ,st[rt].r ,st[rt].maxx,st[rt].sum);        if(k==1) return st[rt].maxx;        else return st[rt].sum;      }       int m=(l+r)>>1;       int ans;    if(k==1) ans=-1000000000;    else ans=0;    if( m>=L) {   //         if(k==1)   ans=max(ans,query(L,R,lson,k)  );        else ans+=query(L,R,lson,k);    }     if(m<R){         if(k==1)    ans=max(ans,query(L,R,rson,k) );          else  ans+=query(L,R,rson,k);     }     push_up(rt);     return ans;}  void _find(int u,int v,int k){        // printf("\n\n %d %d %d\n",u,v,k);    int f1=top[u],f2=top[v];//先找到两个端点的重链顶端节点,如果是轻儿子,就是它本身      int temp=0;    int ans;      if(k==2) ans=0;     else ans=-100000000;    while(f1!=f2){          //从深度较深的开始查询          if(deep[f1]<deep[f2]){              swap(f1,f2);              swap(u,v);          }          //查区间改变         // printf("qujian1: %d %d ----------%d %d  ans:%d\n",u,f1,p[f1],p[u],ans);        if(k==1)  ans=max(ans,query(p[f1],p[u],1,n,1,k)  );   //  u----top[u]    在dfs的时候显然top先放入线段树        else ans+=query(p[f1],p[u],1,n,1,k) ;        u=fa[f1];f1=top[u];      }      //如果f1=f2代表在同一条重链上m,如果u=v 那么也需要单点更新    // if(u==v)      //     return ;    if(deep[u]>deep[v])          swap(u,v);          // printf("qujian2: %d %d ----------%d %d  ans:%d\n",u,v,p[u],p[v],ans);     if(k==1) ans=max(ans,  query(p[u],p[v],1,n,1,k)  );   // v-----u  deep[u]小 那自然先放入线段树     else ans+=query(p[u],p[v],1,n,1,k);     printf("%d\n",ans);}  char op[10];int  main(){    //freopen("1.txt","r",stdin);    while(~scanf("%d",&n)){        init();        int u,v;        for(int i=1;i<n;i++){            scanf("%d %d",&u,&v);            addedge(u,v);            addedge(v,u);        }        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        dfs1(1,0,1);        getpos(1,1);        build(1,n,1);        int q;        scanf("%d",&q);        while(q--){            scanf("%s %d %d",op,&u,&v);             if(op[0]=='C'){                update(p[u],v,1,n,1);   // 更新不是 u 啊,写的也太随意了吧。            }            else{                if(op[1]=='M'){                    _find(u,v,1);                }                else{                    _find(u,v,2);                 }            }        }    }}

http://acm.fzu.edu.cn/problem.php?pid=2082

四、FOJ Problem 2082 过路费(对边进行操作)

没有什么难点,感觉对边的操作没有对点的操作那么熟练,
主要是需要牢记p[u]:代表的是 u与父亲节点连边在线段树中的位置,
因此加完边之后需要更新下val数组。 但是需要先 dfs 和getpos ,因为更新val 时需要用到p数组

#include <bits/stdc++.h>using namespace std;typedef long long ll; /* */  const int MAXN = 50010;  struct Edge  {      int to,next;  }edge[MAXN*2];  int head[MAXN],tot;  int top[MAXN];//top[v]表示v所在的重链的顶端节点  int fa[MAXN]; //父亲节点  int deep[MAXN];//深度  int num[MAXN];//num[v]表示以v为根的子树的节点数  int p[MAXN];//p[v]表示v与其父亲节点的连边在线段树中的位置  int fp[MAXN];//和p数组相反  即 记录线段树中的某个位置的边的起点?int son[MAXN];//重儿子  int pos;   // 每条边在线段树中的位置。int n;  int  val[MAXN];void init()  {      tot = 0;      memset(head,-1,sizeof(head));      pos = 1;//边的序号其实是从1开始?      memset(son,-1,sizeof(son));  }  void addedge(int u,int v)  {      edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;  }  void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son  {      deep[u] = d;      fa[u] = pre;      num[u] = 1;      for(int i = head[u];i != -1; i = edge[i].next)      {          int v = edge[i].to;          //因为路径是双向的,所以不能等于父节点        if(v == pre)  continue;           dfs1(v,u,d+1);          //更新u节点的儿子数目          num[u] += num[v];          if(son[u] == -1 || num[v] > num[son[u]])//求出重儿子即:所有儿子中size 最大的节点v                son[u] = v;      }  }  //因为对于轻儿子来说,top[u]=u,对于重儿子来说,如果son[v]!=-1,那么top[v]=top[son[v]]  void getpos(int u,int sp) //第二遍dfs求出top和p  {      top[u] = sp;      //先找重儿子      if(son[u] != -1)   // 存在重儿子    {          //把边的位置标记一下          p[u] = pos++;          //fp相当于是p的反函数,即记录线段树中某个位置的边 的在树中的起点。        fp[p[u]] = u;          //更新重儿子          getpos(son[u],sp);      }      //如果到了叶子节点      else      {          //不再向下dfs          p[u] = pos++;          fp[p[u]] = u;          return;      }      //更新其他的节点      for(int i = head[u] ; i != -1; i = edge[i].next)      {          int v = edge[i].to;          if(v != son[u] && v != fa[u])              getpos(v,v);   //  轻儿子的top[u]=u    }  }  #define lson l,m,rt<<1  #define rson m+1,r,rt<<1|1  struct node{    int l,r;    ll v;    ll sum;}st[MAXN<<2];void pushup(int rt){      // if(st[rt].l != st[rt].r)         st[rt].sum= st[rt<<1].sum + st[rt<<1|1].sum ;}  void build(int l,int r,int rt){      st[rt].l=l;    st[rt].r=r;          st[rt].v=st[rt].sum=0;        if(l==r){              // printf("bd:%d   =%d\n",l,val[l]);            st[rt].v=val[l];            st[rt].sum=val[l];            return;          }          int m=(l+r)>>1;          build(lson);          build(rson);          pushup(rt);  }  void update(int p,ll x,int l,int r,int rt){  // 单点更新    if(l==r){          st[rt].v=x;        st[rt].sum=x;        return;      }      int m=(l+r)>>1;      if(p<=m)          update(p,x,lson);      else          update(p,x,rson);      pushup(rt);  }  ll query(int L,int R,int l,int r,int rt){    // 区间询问    if( L<=l &&r<=R){          return st[rt].sum;      }    int m=(l+r)>>1;      ll res=0;      if(m>=L)          res+= query(L,R,lson);     if(R>m)          res+= query(L,R,rson);       pushup(rt);    return res;  }ll  _find(int u,int v){   // 找 a-----b 中所有路径的最大值。    int f1=top[u],f2=top[v];//先找到两个端点的重链顶端节点,如果是轻儿子,就是它本身      ll temp=0;      while(f1!=f2){          //从深度较深的开始查询          if(deep[f1]<deep[f2]){              swap(f1,f2);              swap(u,v);          }        //查询一条重链          temp+=query(p[f1],p[u],1,n,1)   ;        u=fa[f1];f1=top[u];      }    //如果f1=f2代表在同一条重链上m,如果u=v代表更新结束  ,这一步的时候  u从更深的地方跳上来,跳至同一重链, 如果u=v那么所有路径都走过一遍。    if(u==v)          return temp;      if(deep[u]>deep[v])          swap(u,v);    return  temp+query(p[son[u]],p[v],1,n,1);   }  ll e[MAXN][3];  int main(){       freopen("1.txt","r",stdin);        int q;        while(~scanf("%d %d",&n,&q)){               init();              for(int i=1;i<n;i++){                  scanf("%d %d %lld",&e[i][0],&e[i][1],&e[i][2]);                  addedge(e[i][0],e[i][1]);                  addedge(e[i][1],e[i][0]);              }               dfs1(1,0,0);              getpos(1,1);            // 现在已经把树剖分完毕。            for(int i=1;i<n;i++){                    if(deep[e[i][0]]<deep[e[i][1]])    // 调整每条路径的父亲,儿子关系。0>1 0为儿子1为父亲                    swap(e[i][0],e[i][1]);                  val[ p[e[i][0]] ]=e[i][2];   //  pi表示i和其父亲连边在线段树中的位置。                // printf("val i=%d  %d  =%d\n",i,p[e[i][0]] ,e[i][2]);            }              build(1,n,1);   // 以val建树            int op;            int u;            ll v;               while(q--){                 scanf("%d %d %lld",&op,&u,&v);                  if(op==0)                      update(p[e[u][0]],v,1,n,1);                  else                      printf("%lld\n",_find(u,v));              }      }      return 0;  }  
原创粉丝点击