Description
After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional roads. We say that huts in the same pair directly connected. XX Village is so special that we can reach any other huts starting from an arbitrary hut. If each road cannot be walked along twice, then the route between every pair is unique.
Since Jiajia earned enough money, Wind became a housewife. Their children loved to go to other kids, then make a simple call to Wind: ‘Mummy, take me home!’
At different times, the time needed to walk along a road may be different. For example, Wind takes 5 minutes on a road normally, but may take 10 minutes if there is a lovely little dog to play with, or take 3 minutes if there is some unknown strange smell surrounding the road.
Wind loves her children, so she would like to tell her children the exact time she will spend on the roads. Can you help her?
Input
The first line contains three integers n, q, s. There are n huts in XX Village, q messages to process, and Wind is currently in hut s. n < 100001 , q < 100001.
The following n-1 lines each contains three integers a, b and w. That means there is a road directly connecting hut a and b, time required is w. 1<=w<= 10000.
The following q lines each is one of the following two types:
Message A: 0 u
A kid in hut u calls Wind. She should go to hut u from her current position.
Message B: 1 i w
The time required for i-th road is changed to w. Note that the time change will not happen when Wind is on her way. The changed can only happen when Wind is staying somewhere, waiting to take the next kid.
Output
For each message A, print an integer X, the time required to take the next child.
Sample Input
3 3 1
1 2 1
2 3 2
0 2
1 2 3
0 3
Sample Output
1
3
分析:
看了一下这道题
好像dalao用LCT就可以A了,我真的一脸mb
还是用这道题练一下树链吧
现在要陆陆续续的把所有学过的数据结构练一练
我们把边权变到点权上
树链剖过之后,就用线段树维护
这样改变边的权值就挺简单了
感觉自己是从头学过,翻了一下自己的blog
发现也没有详细的讲解
dfs1
第一次dfs,我们维护了pre,deep,size以及son
dfs2
第二次dfs,我们维护了top(该节点所在的树链最向上延伸到哪里),
num(该节点在线段树中对应的坐标),shu(线段树中的坐标对应原树中的节点编号)
在dfs的时候,我们其实就完成了一次dfs序的计算
(因为我们先dfs重儿子,再dfs轻儿子)
询问树上路径的权值(u,w):
f1=top[u],f2=top[w]
如果f1!=f2
我们先询问deep大的节点到ta的top的路径值
我这个zz想了好久都不明白到底是怎么回事,看图吧
tip
还记得有一道叫旅行的树剖题
也要把边权转到点上,
边权要转到接近叶子的节点上
一直在纠结在询问两点距离的时候,可能会进行多余计算
我们要怎么解决呢,
其实其余的部分不变,只有在asksum的最后有一点小改变
看图解释
这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=1000005;
int size[N],pre[N],deep[N],son[N],top[N],shu[N],num[N],cnt=0;
struct node{
int x,y,nxt,v;
};
node way[N<<1];
int n,q,s,st[N],tot=0,val[N],wz[N];
struct nd{
int x,y,sum;
};
nd t[N<<2];
void add(int u,int w,int z)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
tot++;
way[tot].x=w;way[tot].y=u;way[tot].v=z;way[tot].nxt=st[w];st[w]=tot;
}
void dfs1(int now,int fa,int dep)
{
pre[now]=fa;
deep[now]=dep;
size[now]=1;
int mx=0;
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa)
{
dfs1(way[i].y,now,dep+1);
val[way[i].y]=way[i].v; wz[(i+1)/2]=way[i].y; //叶子结点记录v
size[now]+=size[way[i].y];
if (size[way[i].y]>mx){
mx=size[way[i].y];
son[now]=way[i].y;
}
}
}
void dfs2(int now,int fa)
{
if (son[pre[now]]!=now) top[now]=now; //轻链
else top[now]=top[fa];
num[now]=++cnt;
shu[num[now]]=now;
if (son[now]) //not a leaf
{
dfs2(son[now],now);
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa&&way[i].y!=son[now])
dfs2(way[i].y,now);
}
}
void build(int bh,int l,int r)
{
t[bh].x=l;t[bh].y=r;
if (l==r){
t[bh].sum=val[shu[l]];
return;
}
int mid=(l+r)>>1;
build(bh<<1,l,mid);
build(bh<<1|1,mid+1,r);
t[bh].sum=t[bh<<1].sum+t[bh<<1|1].sum;
}
void change(int bh,int p,int z)
{
if (t[bh].x==t[bh].y)
{
t[bh].sum=z;
return;
}
int mid=(t[bh].x+t[bh].y)>>1;
if (p<=mid) change(bh<<1,p,z);
else change(bh<<1|1,p,z);
t[bh].sum=t[bh<<1].sum+t[bh<<1|1].sum;
}
int ask(int bh,int l,int r)
{
if (t[bh].x>=l&&t[bh].y<=r)
return t[bh].sum;
int mid=(t[bh].x+t[bh].y)>>1;
int ans=0;
if (l<=mid) ans+=ask(bh<<1,l,r);
if (r>mid) ans+=ask(bh<<1|1,l,r);
return ans;
}
int asksum(int u,int w)
{
int ans=0;
int f1=top[u];
int f2=top[w];
while (f1!=f2)
{
if (deep[f1]<deep[f2]) swap(u,w);
f1=top[u]; f2=top[w];
ans+=ask(1,num[f1],num[u]);
u=pre[f1]; ///
f1=top[u];
}
if (u==w) return ans;
if (num[u]>num[w]) swap(u,w);
ans+=ask(1,num[son[u]],num[w]); //num[son[u]]
return ans;
}
int main()
{
while(scanf("%d%d%d",&n,&q,&s)!=EOF)
{
memset(st,0,sizeof(st));
for (int i=1;i<n;i++)
{
int u,w,z;
scanf("%d%d%d",&u,&w,&z);
add(u,w,z);
}
dfs1(1,0,1);
dfs2(1,0);
build(1,1,n);
for (int i=1;i<=q;i++)
{
int opt,u,w;
scanf("%d",&opt);
if (opt==0)
{
scanf("%d",&u);
printf("%d
",asksum(u,s)); //询问树链
s=u;
}
else
{
scanf("%d%d",&u,&w);
change(1,num[wz[u]],w); //第i条边的信息记录在了哪个节点上
}
}
}
return 0;
}