UESTC_树上的距离 2015 UESTC Training for Graph Theory<Problem E>

E - 树上的距离

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

Submit Status

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

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

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

Input

第一行一个数n,表示点的个数。接下来n−1行,每行3个数u,v,w,表示u,v间有权为w的边。边按照输入顺序从1到n−1编号。输入保证为一颗树。 (2≤n≤105,1≤u,v≤n,1≤w≤1000)

之后输入一个数q,表示询问个数。最后有q行,每行第一个数op(op=1或2)为操作类型。

当op=1时,输入u,v表示询问u,v间的距离。 (u≠v,1≤u,v≤n)

当op为2时,输入id,w表示把编号为id的边的权值改为w。 (1≤q≤105,1≤id≤n−1,1≤w≤1000)

Output

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

Sample input and output

Sample Input Sample 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\n",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;
}
时间: 2024-10-12 13:34:59

UESTC_树上的距离 2015 UESTC Training for Graph Theory<Problem E>的相关文章

UESTC_王之盛宴 2015 UESTC Training for Graph Theory&lt;Problem K&gt;

K - 王之盛宴 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 王征战回来了,为了庆祝胜利,王准备请大家吃饭! 于是n个人来到了一家豪华餐厅,这家餐厅有一张长————————长的桌子,每个人只能坐在桌子的南北两侧 一行人中,有p对A关系,m对B关系,如果u和v有A关系,则u和v必须坐在不同侧,如果u和v有B关系,则u和v必须坐在同侧 如果一种座位安

UESTC_方老师和农场 2015 UESTC Training for Graph Theory&lt;Problem L&gt;

L - 方老师和农场 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 方老师重新开了一家农场,农场一共有N个节点和M条双向边,但是有一个很大的问题就是有比如一个农场A到达农场B只有一条路径,问至少添加多少条边使得任意两个农场之间的路径多于一条. Input 多组数据,EOF结束. 第1行:N和M. 第2到第M+1行:每一行2个数Ui和Vi,表示Ui到

UESTC_秋实大哥带我飞 2015 UESTC Training for Graph Theory&lt;Problem B&gt;

B - 秋实大哥带我飞 Time Limit: 300/100MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 然而题目和题面并没有什么关系. 给出n个点,m条带权无向边,问你从1号点到n号点的最短路中有多少种走法? Input 第一行两个数n,m分别表示点的个数和边的个数. (2≤n≤2000,1≤m≤2000) 接下来m行,每行3个数u,v,w表示u号点到v号点有一条距离为w的边.(1≤u

UESTC_排名表 2015 UESTC Training for Graph Theory&lt;Problem I&gt;

I - 排名表 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 暑假前集训已经过了一半了,我们将会把当前排名公布出来.但是此刻秋实大哥却心急火燎,因为他不慎把排名删除了. 一共有n个人参加排名,每个人都有一个名次,没有哪两个人的名次是相同的.现在秋实大哥掌握的一些情报,比如Ai的名次要先于Bi.(编号从1开始) 你能帮秋实大哥恢复出排名表吗? Inp

UESTC_传输数据 2015 UESTC Training for Graph Theory&lt;Problem F&gt;

F - 传输数据 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 机房里面有m台电脑,n台网线,每条网线都每秒中最多传送的数据量,现在需要你计算从标号为1的电脑传送数据到编号为m的电脑,问一秒内最多传送多少数据? Input 第1行: 两个用空格分开的整数N(0≤N≤200)和 M(2≤M≤200).N网线的数量,M是电脑的数量. 第二行到第N+1行

UESTC_秋实大哥与连锁快餐店 2015 UESTC Training for Graph Theory&lt;Problem A&gt;

A - 秋实大哥与连锁快餐店 Time Limit: 9000/3000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 成大事者,不惟有超世之才,亦有坚忍不拔之志. 秋实大哥开了一家快餐店之后,由于人赢光环的影响,很快就赚得了大量的资金.为了继续实现心中的远大的理想,他打算在全国各地开设分店赚大钱.假设现在有n家快餐店(其中有至少有一家是旗舰店)分布在二维平面上,第i家快餐店的坐标为(xi,

UESTC_韩爷的情书 2015 UESTC Training for Graph Theory&lt;Problem H&gt;

H - 韩爷的情书 Time Limit: 6000/2000MS (Java/Others)     Memory Limit: 262144/262144KB (Java/Others) Submit Status 某年某月某日,韩爷被妹子表白了\o/ 同时,韩爷收到了来自妹子的情书.在好奇心的驱使下,众人想要一览究竟. 显然,羞涩韩爷是不会把情书直接拿出来的. 假设情书长度为n+2,韩爷从中提取出n个长度为3的连续字符串,分给了n个人. 现在这n个人向你求助,能否帮他们把情书恢复出来. I

UESTC_秋实大哥与时空漫游 2015 UESTC Training for Graph Theory&lt;Problem C&gt;

C - 秋实大哥与时空漫游 Time Limit: 4500/1500MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 秋实大哥通过全国的连锁快餐店发家致富,赚了大钱,接下来他打算通过这些钱实现他的另一个梦想————遨游太空,漫游星际. 秋实大哥满怀期待的出发了. .......啦啦啦啦啦啦啦啦啦...... 最后,秋实大哥花完了钱,觉得是时候回地球继续赚钱和过节了. 但是却被告知回地球的专机

UESTC_小panpan学图论 2015 UESTC Training for Graph Theory&lt;Problem J&gt;

J - 小panpan学图论 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 小panpan不会图论,所以图论专题他非常刻苦地学习图论. 今天他认真地学习了萌神的ppt,学习了一下Floyd算法,手持两把锟斤拷的他, 口中疾呼烫烫烫,马上找了到OJ上找了道FLoyd的题: n个点,m边的无向连通图,无重边,无自环,每条边的长度都是1,求任意两点之间的