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. 福建省队集训被虐记——DAY2

    唉--第二天依然被虐--但是比第一天好一点--我必须负责任的指出:志灿大神出的题比柯黑的不知道靠谱到哪里去了--柯黑出的简直不可做 但是被虐的命运是无法改变的--求各位神犇别D我 黄巨大真是强啊,不愧 ...

  2. poj 3190 Stall Reservations 贪心 + 优先队列

    题意:给定N头奶牛,每头牛有固定的时间[a,b]让农夫去挤牛奶,农夫也只能在对应区间对指定奶牛进行挤奶, 求最少要多少个奶牛棚,使得在每个棚内的奶牛的挤奶时间不冲突. 思路:1.第一个想法就是贪心,对 ...

  3. hdoj 3400 三分

    两次三分 #include <iostream> #include <cstdio> #include <cstring> #include <cmath&g ...

  4. 高性能WEB开发(6) - web性能測试工具推荐

    WEB性能測试工具主要分为三种.一种是測试页面资源载入速度的,一种是測试页面载入完成后页面呈现.JS操作速度的,另一种是整体上对页面进行评价分析,以下分别对这些工具进行介绍,假设谁有更好的工具也请一起 ...

  5. [Regular Expressions] Match the Same String Twice

    Regular Expression Backreferences provide us a method to match a previously captured pattern a secon ...

  6. last与lastlog命令

    lastlog 列出所有用户最后登录的时间和登录终端的地址,如果此用户从来没有登录,则显示:**Never logged in**last 列出用户所有的登录时间和登录终端的地址

  7. Android学习笔记--JNI的使用方法

    1.JNI是什么 JNI是Java Native Interface的缩写,它提供若干的API实现Java与其他语言之间的通信.而Android Framework由基于Java语言的的Java层与基 ...

  8. jquery的验证实例方法

    上一篇介绍了js的正则验证法,这一片就用jquery来实例运行一下其中的几个方法 Js部分 <script> $(function(){ var ok1=false; var ok2=fa ...

  9. MFC串口通信

    1.串口的操作可以有两种操作方式:同步操作方式和重叠操作方式(又称为异步操作方式). 同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞主线程,但是仍然会阻塞监听线程) ...

  10. (转) Overloads and templates

    Overloaded functions In C++, two different functions can have the same name if their parameters are ...