zoukankan      html  css  js  c++  java
  • UESTC_树上的距离 2015 UESTC Training for Graph Theory<Problem E>

    E - 树上的距离

    Time Limit: 2000/1000MS (Java/Others)     Memory Limit: 262143/262143KB (Java/Others)
     

    给你一棵带权树,边权表示两点间的距离。有如下两种操作:

    1. 询问两点间的最短距离。
    2. 修改一条边权值。

    对每个操作1,回答两点间的距离。

    Input

    第一行一个数n,表示点的个数。接下来n1行,每行3个数uvw,表示uv间有权为w的边。边按照输入顺序从1n1编号。输入保证为一颗树。 (2n1051u,vn1w1000

    之后输入一个数q,表示询问个数。最后有q行,每行第一个数opop=12)为操作类型。

    op=1时,输入uv表示询问uv间的距离。 (uv1u,vn

    op2时,输入idw表示把编号为id的边的权值改为w。 (1q1051idn11w1000

    Output

    对于对每个操作1,输出一行,回答两点间的距离。

    Sample input and output

    Sample InputSample Output
    5
    1 2 2
    2 3 3
    1 5 1
    2 4 4
    5
    1 1 3
    1 2 5
    2 1 1
    2 3 3
    1 2 5
    5
    3
    4

    解题报告:

    这是一道 LCA + 欧拉序列 + 线段树题目

    首先我们容易得出下列这个式子

    设 distance(x) 为树上的点 x 到根的距离,设u为x,y的最近公共祖先

    则distance of (x – y) = distance(x) + distance(y) – 2*distance(u)

    那么我们该如何求得LCA呢

    这里我采用的是tarjan离线处理所有询问.

    一遍dfs处理所有询问的LCA,复杂度为O(n+q)

    之后我们用一次dfs将树转为线性结构.

    即记录这个点的入时间戳,也记录这个点的出时间戳.

    容易得到[ 入时间戳 + 1 , 出时间戳 ] 恰好包含了这个点及其儿子

    这样,本题就转换成了线段树区间更新 + 点查询的题目

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #define pb push_back
    using namespace std;
    const int maxn = 2e5 + 20;
    
    typedef struct Edge
    {
     int u,v,w;
     Edge(int u,int v,int w)
      {
         this->u = u , this->v = v , this->w = w ;     
      }    
    };
    
    typedef struct treenode
    {
      int l,r,lazy,sum;
      void updata(int x)
       {
           lazy += x;
           sum += (r-l+1)*x;    
       }    
    };
    
    typedef struct querynode
    {
      int type,t1,t2,lca;
    };
    
    typedef struct tarjan
    {
      int v , ansid;
      tarjan(int v,int ansid)
       {
             this->v = v ,this->ansid = ansid;
       }
    };
    
    
    treenode tree[maxn*8];
    
    
    void build_tree(int o,int l,int r)
    {
       tree[o].l = l , tree[o].r = r ; tree[o].sum = tree[o].lazy = 0;
       if (r > l)
        {
            int mid = l + (r-l)/2;
            build_tree(2*o,l,mid);
            build_tree(2*o+1,mid+1,r);
        }
    }
    
    inline void push_up(int x)
    {
       tree[x].sum = tree[2*x].sum + tree[2*x+1].sum;
    }
    
    inline void push_down(int x)
    {
       int lazy = tree[x].lazy;
       if (lazy)
        tree[2*x].updata(lazy),tree[2*x+1].updata(lazy);
       tree[x].lazy = 0;
    }
    
    void updata(int ql,int qr,int o,int v)
    {
       int l = tree[o].l , r = tree[o].r;
       if (ql <= l && qr >= r )
        tree[o].updata(v);
       else
        {
            int mid = l + (r-l)/2;
            push_down(o);
            if (mid >= ql)
             updata(ql,qr,2*o,v);
            if (mid < qr)
             updata(ql,qr,2*o+1,v);
            push_up(o);
        }
    }
    
    int querysum(int ql,int qr,int o)
    {
       int l = tree[o].l , r = tree[o].r;
       if (ql <= l && qr >= r)
        return tree[o].sum;
       else
        {
            int mid = l + (r-l)/2;
            push_down(o);
            int res = 0;
            if (mid >= ql)
             res += querysum(ql,qr,2*o);
            if (mid < qr)
             res += querysum(ql,qr,2*o+1);
            push_up(o);
            return res;
        }
    }
    
    int n,euler[maxn*2],id[maxn][2],sum[maxn*2],deapth[maxn*2],tot = 1,pre[maxn],father[maxn];
    vector<Edge>New_next[maxn],e;
    bool vis[maxn];
    querynode q[maxn];
    vector<tarjan>use[maxn];
    
    inline int find_set(int x)
    {
       return x != pre[x] ? pre[x] = find_set(pre[x]) : x;
    }
    
    inline void union_set(int x,int y)
    {
       pre[find_set(x)] = y;
    }
    
    void init_id(int cur)
    {
       id[cur][0] = tot++;
       for(int i = 0 ; i < New_next[cur].size() ; ++ i)
        {
            int nextnode = New_next[cur][i].v;
            if (nextnode == father[cur])
             continue;
            init_id(nextnode);
        }
       id[cur][1] = tot++;
    }
    
    void init_tarjan(int cur)
    {
       pre[cur] = cur;
       vis[cur] = true;
       for(int i = 0 ; i < New_next[cur].size() ; ++ i)
        {
            int nextnode = New_next[cur][i].v;
            if (nextnode == father[cur])
             continue;
            init_tarjan(nextnode);
            union_set(nextnode,cur);
        }
       for(int i = 0 ; i < use[cur].size() ; ++ i)
        {
            int v = use[cur][i].v , ansid = use[cur][i].ansid;        
            if (vis[v])
             q[ansid].lca = find_set(v);
        }
    }
    
    void fatherset(int cur,int fat)
    {
       father[cur] = fat;
       for(int i = 0 ; i < New_next[cur].size() ; ++ i)
        {
            int nextnode = New_next[cur][i].v;
            if (nextnode == fat)
             continue;
            fatherset(nextnode,cur);
        }
    }
    
    
    
    int main(int argc,char *argv[])
    {
      scanf("%d",&n);
      memset(sum,0,sizeof(sum));
      memset(vis,false,sizeof(vis));
      for(int i = 0 ; i < n - 1 ; ++ i)
       {
             int u,v,w;
             scanf("%d%d%d",&u,&v,&w);
             e.pb(Edge(u,v,w));
             New_next[u].pb(Edge(u,v,w));
             New_next[v].pb(Edge(v,u,w));
       }
      fatherset(1,0);
      init_id(1);
      build_tree(1,1,tot+5);
      for(int i = 0 ; i < e.size() ; ++ i)
       {
             int u = e[i].u , v = e[i].v , w = e[i].w;
             if (father[u] == v)
              {
                 swap(u,v);
                 swap(e[i].u,e[i].v);
           }
             updata(id[v][0]+1,id[v][1],1,w);
       }
      int qnumber;
      scanf("%d",&qnumber);
      for(int i = 0 ; i < qnumber ; ++ i)
       {
             int type,t1,t2;
             scanf("%d%d%d",&type,&t1,&t2);
             q[i].type = type,q[i].t1 = t1 , q[i].t2 = t2;
             if (type & 1)
              {
                    if (father[t1] == t2)
                  swap(q[i].t1,q[i].t2);
                    use[t1].pb(tarjan(t2,i));
                    use[t2].pb(tarjan(t1,i));
           }
       }
      init_tarjan(1); //离线处理
      for(int i = 0 ; i < qnumber ; ++ i)
       {
             int type = q[i].type ,t1 = q[i].t1 ,t2 = q[i].t2 ;
             if (type & 1)
              {
                    int lca = q[i].lca;
                    int p1 = querysum(id[t1][1],id[t1][1],1);
                    int p2 = querysum(id[t2][1],id[t2][1],1);      
                    int p3 = querysum(id[lca][1],id[lca][1],1);
                    printf("%d
    ",p1+p2-2*p3);
           }
          else
           {
                 int u = e[t1-1].u, v = e[t1-1].v;
                 updata(id[v][0]+1,id[v][1],1, t2 - e[t1-1].w);
                 e[t1-1].w = t2;
           }
       }
      return 0;
    }
  • 相关阅读:
    bzoj1005: [HNOI2008]明明的烦恼(prufer+高精度)
    bzoj1211: [HNOI2004]树的计数(prufer序列+组合数学)
    bzoj1430: 小猴打架(prufer序列)
    bzoj1029: [JSOI2007]建筑抢修(堆+贪心)
    bzoj1053: [HAOI2007]反素数ant
    [HNOI2012]双十字
    [HNOI2012]矿场搭建
    [HNOI2012]集合选数
    [HNOI2013]消毒
    POJ2449 Remmarguts' Date
  • 原文地址:https://www.cnblogs.com/Xiper/p/4570658.html
Copyright © 2011-2022 走看看