题意:给定一棵有n( n < 100001 )个结点的带边权的树,处理以下一共q(q < 100001)个操作:
1,改变树的一条边的权;
2,求给定点和某点的距离,后者是编号为1的结点,若是第一次执行操作2,否则为上次执行操作2的给定点。
没有了操作1,这题就是典型的LCA,于是怎样有效地执行操作1就是这题的关键。还记得LCA到RMQ的转化吗点我,过程中DFS会生成一条回路,并且产生一个从遍历次序到结点编号的满射,我们称它为order[]。我们知道,若以结点到根的距离作为树的深度,如果一条边的权增加了delta,那么这条边链接的子树内的所有结点的深度都增加了delta。又因为子树内的结点的遍历次序是连续的,所以我们可以建立从 遍历次序 到 到根的距离的映射dist[],于是每次执行操作1只需对dist[]的一片连续区域作修改即可,可以用线段树或者树状数组。
搞定了操作1,我们发现操作2也被搞出来了,因为LCA(u,v)=order[RMQ(dist[出现u的任意遍历序号...出现v的任意遍历序号])],可能这是出题者的意图吧。
#include
<
iostream
>
#include
<
vector
>
#include
<
cmath
>
using
namespace
std;
#define
MAXN 200005
#define
LOG 20
typedef pair
<
int
,
int
>
PAIR;
int
order[MAXN],ecnt,dist[MAXN],first[MAXN],last[MAXN],n,q,st,p[MAXN],maxorder,c[MAXN],mn[MAXN][LOG],b[MAXN];
//
first[u]表示u首次出现的遍历序号,last[u]表示u最后出现的遍历序号
bool
visited[MAXN];
struct
Edge{
int
v,weight,next;
}edg[MAXN];
void
init(){
ecnt
=
0
;
memset(p,
-
1
,
sizeof
(p));
memset(dist,
0
,
sizeof
(dist));
maxorder
=
1
;
memset(visited,
false
,
sizeof
(visited));
memset(c,
0
,
sizeof
(c));
}
void
dfs(
int
pre,
int
u,
int
w){
int
i,v,ordertmp;
visited[u]
=
true
;
last[u]
=
first[u]
=
maxorder;
order[maxorder]
=
u;
dist[maxorder]
=
dist[last[pre]]
+
w;
ordertmp
=
maxorder
++
;
for
(i
=
p[u];i
!=-
1
;i
=
edg[i].next){
v
=
edg[i].v;
if
(
!
visited[v]){
dfs(u,v,edg[i].weight);
order[maxorder]
=
u;
last[u]
=
maxorder;
dist[maxorder]
=
dist[ordertmp];
maxorder
++
;
}
}
}
////////////////////////////////////////////////////////////////////////
//
//
树状数组
inline
int
lowbit(
int
x){
return
x
&
(
-
x);
}
int
down(
int
x){
int
i,res
=
0
;
for
(i
=
x;i
>
0
;i
-=
lowbit(i))
res
+=
c[i];
return
res;
}
void
up(
int
x,
int
t){
int
i;
for
(i
=
x;i
<
maxorder;i
+=
lowbit(i))
c[i]
+=
t;
}
void
build(){
int
i;
for
(i
=
1
;i
<
maxorder;i
++
)
b[i]
=
dist[i]
-
dist[i
-
1
];
for
(i
=
1
;i
<
maxorder;i
++
){
up(i,b[i]);
}
}
////////////////////////////////////////////////////////////////////////
//
//
spares table
void
preprocess(){
int
i,j;
for
(i
=
1
;i
<
maxorder;i
++
)
mn[i][
0
]
=
i;
for
(j
=
1
;(
1
<<
j)
<=
maxorder;j
++
){
for
(i
=
1
;i
+
(
1
<<
j)
-
1
<
maxorder;i
++
){
if
(dist[mn[i][j
-
1
]]
<=
dist[mn[i
+
(
1
<<
(j
-
1
))][j
-
1
]])
mn[i][j]
=
mn[i][j
-
1
];
else
mn[i][j]
=
mn[i
+
(
1
<<
(j
-
1
))][j
-
1
];
}
}
}
int
RMQ(
int
i,
int
j){
if
(i
>
j){
int
t
=
i;
i
=
j;
j
=
t;
}
int
k
=
log((
double
)j
-
i
+
1
)
/
log((
double
)
2
);
if
(dist[mn[i][k]]
<=
dist[mn[j
-
(
1
<<
k)
+
1
][k]])
return
mn[i][k];
else
return
mn[j
-
(
1
<<
k)
+
1
][k];
}
////////////////////////////////////////////////////////////////////////
//
//
main
int
main(){
int
i,j,u,v,weight,flag,w;
init();
vector
<
PAIR
>
vec;
scanf(
"
%d%d%d
"
,
&
n,
&
q,
&
st);
for
(i
=
0
;i
<
n
-
1
;i
++
){
scanf(
"
%d%d%d
"
,
&
u,
&
v,
&
weight);
vec.push_back(make_pair(u,v));
edg[ecnt].next
=
p[u];
edg[ecnt].v
=
v;
edg[ecnt].weight
=
weight;
p[u]
=
ecnt
++
;
edg[ecnt].next
=
p[v];
edg[ecnt].v
=
u;
edg[ecnt].weight
=
weight;
p[v]
=
ecnt
++
;
}
dfs(
1
,
1
,
0
);
//
for(i=1;i<maxorder;i++)
//
printf("%d ",order[i]);
//
printf("\n");
//
for(i=1;i<maxorder;i++)
//
printf("%d ",dist[i]);
//
printf("\n");
//
for(i=1;i<=n;i++)
//
printf("%d ",first[i]);
//
printf("\n");
//
for(i=1;i<=n;i++)
//
printf("%d ",last[i]);
//
printf("\n");
build();
preprocess();
for
(i
=
0
;i
<
q;i
++
){
scanf(
"
%d
"
,
&
flag);
if
(flag){
scanf(
"
%d%d
"
,
&
j,
&
weight);
j
--
;
u
=
vec[j].first;
v
=
vec[j].second;
if
(dist[first[u]]
>
dist[first[v]]){
int
t
=
u;
u
=
v;
v
=
t;
}
w
=
down(first[v])
-
down(first[u]);
up(first[v],weight
-
w);
if
(last[v]
+
1
<
maxorder)
up(last[v]
+
1
,w
-
weight);
}
else
{
scanf(
"
%d
"
,
&
u);
v
=
order[RMQ(first[u],first[st])];
printf(
"
%d\n
"
,down(first[u])
+
down(first[st])
-
2
*
down(first[v]));
st
=
u;
}
}
return
0
;
}