Description
给你一棵树 2种操作0 x 求当前点s到x的最短路 然后当前的位置为x; 1 i x 将第i条边的权值置为x
Input
第一行三个整数n,q和s表示点数,操作数和当前位置,之后n-1行每行三个整数a b c表示a,b之间有一条权值为c的边,最后q行每行一个操作
Output
对于每个查询,输出查询结果
Sample Input
3 3 1
1 2 1
2 3 2
0 2
1 2 3
0 3
Sample Output
1
3
Solution
两个点a,b之间的最短路即为a到根节点的距离+b到根节点的距离-2*lca(a,b)到根节点的距离,那么树链剖分之后只要我们求出每个点到根节点的距离,问题就转化为单点修改(此处用前缀和优化将区间修改变成单点修改)和区间求和问题,用树状数组存储每个节点到根节点距离,由于这道题是边权,所以我是用树链剖分之后每条边的终点(即在树中深度较深的那个点)的dfs序值来表示这条边的编号,之后就是树状数组的单点更新与区间查操作了
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 111111
struct Edge
{
int to,next;
}E[2*maxn];
int n,q,s,e[maxn][3],head[maxn],cnt,idx,size[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],l[maxn],r[maxn],bit[maxn];
void init()
{
cnt=idx=0;
memset(head,-1,sizeof(head));
dep[1]=fa[1]=size[0]=0;
memset(son,0,sizeof(son));
memset(bit,0,sizeof(bit));
}
void add(int u,int v)
{
E[cnt].to=v;
E[cnt].next=head[u];
head[u]=cnt++;
}
void dfs1(int u)
{
size[u]=1;
for(int i=head[u];~i;i=E[i].next)
{
int v=E[i].to;
if(v!=fa[u])
{
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
size[u]+=size[v];
if(size[son[u]]<size[v]) son[u]=v;
}
}
}
void dfs2(int u,int topu)
{
top[u]=topu;
l[u]=++idx;
if(son[u]) dfs2(son[u],top[u]);
for(int i=head[u];~i;i=E[i].next)
{
int v=E[i].to;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
r[u]=idx;
}
void update(int x,int v)
{
while(x<=n)
{
bit[x]+=v;
x+=x&(-x);
}
}
int getsum(int x)
{
int ans=0;
while(x>0)
{
ans+=bit[x];
x-=x&(-x);
}
return ans;
}
int lca(int u,int v)
{
int top1=top[u],top2=top[v];
while(top1!=top2)
{
if(dep[top1]<dep[top2])
{
swap(top1,top2);
swap(u,v);
}
u=fa[top1];
top1=top[u];
}
return dep[u]<dep[v]?u:v;
}
int main()
{
while(~scanf("%d%d%d",&n,&q,&s))
{
init();
int u,v,i,w,op;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
u=e[i][0],v=e[i][1];
add(u,v);add(v,u);
}
dfs1(1);
dfs2(1,1);
for(int i=1;i<n;i++)
{
if(dep[e[i][0]]>dep[e[i][1]])
swap(e[i][0],e[i][1]);
update(l[e[i][1]],e[i][2]);
update(r[e[i][1]]+1,-e[i][2]);
}
while(q--)
{
scanf("%d",&op);
if(op)
{
scanf("%d%d",&i,&w);
update(l[e[i][1]],w-e[i][2]);
update(r[e[i][1]]+1,e[i][2]-w);
e[i][2]=w;
}
else
{
scanf("%d",&u);
int d1=getsum(l[u]),d2=getsum(l[s]),d3=getsum(l[lca(s,u)]);
printf("%d\n",d1+d2-2*d3);
s=u;
}
}
}
return 0;
}