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 + ; 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+)*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*]; void build_tree(int o,int l,int r)
{
tree[o].l = l , tree[o].r = r ; tree[o].sum = tree[o].lazy = ;
if (r > l)
{
int mid = l + (r-l)/;
build_tree(*o,l,mid);
build_tree(*o+,mid+,r);
}
} inline void push_up(int x)
{
tree[x].sum = tree[*x].sum + tree[*x+].sum;
} inline void push_down(int x)
{
int lazy = tree[x].lazy;
if (lazy)
tree[*x].updata(lazy),tree[*x+].updata(lazy);
tree[x].lazy = ;
} 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)/;
push_down(o);
if (mid >= ql)
updata(ql,qr,*o,v);
if (mid < qr)
updata(ql,qr,*o+,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)/;
push_down(o);
int res = ;
if (mid >= ql)
res += querysum(ql,qr,*o);
if (mid < qr)
res += querysum(ql,qr,*o+);
push_up(o);
return res;
}
} int n,euler[maxn*],id[maxn][],sum[maxn*],deapth[maxn*],tot = ,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][] = tot++;
for(int i = ; i < New_next[cur].size() ; ++ i)
{
int nextnode = New_next[cur][i].v;
if (nextnode == father[cur])
continue;
init_id(nextnode);
}
id[cur][] = tot++;
} void init_tarjan(int cur)
{
pre[cur] = cur;
vis[cur] = true;
for(int i = ; 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 = ; 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 = ; 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,,sizeof(sum));
memset(vis,false,sizeof(vis));
for(int i = ; i < n - ; ++ 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(,);
init_id();
build_tree(,,tot+);
for(int i = ; 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][]+,id[v][],,w);
}
int qnumber;
scanf("%d",&qnumber);
for(int i = ; 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 & )
{
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(); //离线处理
for(int i = ; i < qnumber ; ++ i)
{
int type = q[i].type ,t1 = q[i].t1 ,t2 = q[i].t2 ;
if (type & )
{
int lca = q[i].lca;
int p1 = querysum(id[t1][],id[t1][],);
int p2 = querysum(id[t2][],id[t2][],);
int p3 = querysum(id[lca][],id[lca][],);
printf("%d\n",p1+p2-*p3);
}
else
{
int u = e[t1-].u, v = e[t1-].v;
updata(id[v][]+,id[v][],, t2 - e[t1-].w);
e[t1-].w = t2;
}
}
return ;
}

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

  1. UESTC_王之盛宴 2015 UESTC Training for Graph Theory<Problem K>

    K - 王之盛宴 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit  ...

  2. UESTC_方老师和农场 2015 UESTC Training for Graph Theory<Problem L>

    L - 方老师和农场 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submi ...

  3. UESTC_秋实大哥带我飞 2015 UESTC Training for Graph Theory<Problem B>

    B - 秋实大哥带我飞 Time Limit: 300/100MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit ...

  4. UESTC_小panpan学图论 2015 UESTC Training for Graph Theory<Problem J>

    J - 小panpan学图论 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) S ...

  5. UESTC_排名表 2015 UESTC Training for Graph Theory<Problem I>

    I - 排名表 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit S ...

  6. UESTC_韩爷的情书 2015 UESTC Training for Graph Theory<Problem H>

    H - 韩爷的情书 Time Limit: 6000/2000MS (Java/Others)     Memory Limit: 262144/262144KB (Java/Others) Subm ...

  7. UESTC_传输数据 2015 UESTC Training for Graph Theory<Problem F>

    F - 传输数据 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit  ...

  8. UESTC_邱老师的脑残粉 2015 UESTC Training for Graph Theory<Problem D>

    D - 邱老师的脑残粉 Time Limit: 12000/4000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Sub ...

  9. UESTC_秋实大哥与时空漫游 2015 UESTC Training for Graph Theory<Problem C>

    C - 秋实大哥与时空漫游 Time Limit: 4500/1500MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Su ...

随机推荐

  1. 独立写作(A or B)

    开头:On contemporary society(一般的背景)/ With the advent of the technologically advanced society (the info ...

  2. poj 2229 Sumsets(dp 或 数学)

    Description Farmer John commanded his cows to search . Here are the possible sets of numbers that su ...

  3. Hibernaate事务管理

    Hibernate使用session时需要继承HibernateDaoSupport对象 HibernateDaoSupport对象中包含默认的getSession()方法,但不可以通过该方法直接启动 ...

  4. 单调队列-Hdu-4122-Alice's mooncake shop

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4122 题目意思: 一家月饼店,有n个订单,从2001年1月1日0时开始24小时营业开m个小时,且每个 ...

  5. Sql Server 函数的操作实例!(执行多条语句,返回Select查询后的临时表)

    Sql Server 函数的操作实例!(执行多条语句,返回Select查询后的临时表) SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ==== ...

  6. 网页http请求的整个过程

    这几天看一个讲解一个网页从我们输入地址到显示在我们面前的一个讲解,是我对http又有了一个完整的了解,现在做一下整个流程的记录,虽然不是很详细,但是整个过程是完整的.如果不对,请指正! 打开浏览器,地 ...

  7. AngularJS Directive - 开场小介绍(转)

    Directive其实就是让html变得更强大的一种方法.它可以根据需求对dom变形,或注入行为. 觉得它很神秘么,其实一点儿也不神秘,只要开始使用AngularJS了,就一定在使用着Directiv ...

  8. lucene评分推导公式

    在进行Lucene的搜索过程解析之前,有必要单独的一张把Lucene score公式的推导,各部分的意义阐述一下.因为Lucene的搜索过程,很重要的一个步骤就是逐步的计算各部分的分数. Lucene ...

  9. Python3.5入门学习记录-File

    在Python中,操作文件对象使用open函数来创建,下表列出了常用的操作file的函数: 序号 方法及描述 1.file.close() 关闭文件.关闭后文件不能再进行读写操作. 2.file.fl ...

  10. Js 日期处理

    Js获取当前日期时间 var myDate = new Date(); myDate.getFullYear();    //获取完整的年份(4位,1970-????)  2014myDate.get ...