这个寒假过得……不是用充实二字就能简简单单形容得了的啊!但不论如何,寒假毕竟是寒假。所以既然是最后一天,那么就笑着迎接它的终结吧。
今天要来总结一下树上路径修改,单点查询的操作。
题目
WOJ#2230 树上修改
WOJ题目链接
题目描述
有n个节点N-1条边,这是一颗树,有2个操作:
1 x y v:表示将节点x到y最短路径上所有的点的权值+v
2 x:表示查询节点x的权值
开始的时候每个节点的权值是0
输入
第一行是数N,表示N个节点 接下来n-1行,每行描述了n-1条边。
接下来是一个数q表示有q次查询与询问 接下来q行,格式如题。
输出
若干行(官方省略)
样例
- 输入样例
3
1 2
2 3
3
1 1 2 5
1 1 3 2
2 2 - 输出样例
7
说明
n<=1e5 q<=1e5
题意
嘛,大概就是,路径修改,单点查询。
思路
首先,考虑树上两点间的路径修改。依次修改显然是不现实的,这时候就考虑差分。
由
x
x
x点到
y
y
y点的路径上
+
v
+v
+v,就可以转化为由
x
x
x到
r
o
o
t
root
root的路径
+
v
+v
+v,再由
y
y
y到
r
o
o
t
root
root的路径
+
v
+v
+v,为了处理掉
r
o
o
t
root
root以上的部分,再由
l
c
a
(
x
,
y
)
lca(x,y)
lca(x,y)到
r
o
o
t
root
root的路径
−
v
-v
−v,可这时
l
c
a
(
x
,
y
)
lca(x,y)
lca(x,y)就被清零了,所以再加上一个
v
v
v。
其次,考虑如果
x
x
x的修改对
y
y
y有贡献,只有
x
x
x在
y
y
y的子树中才会产生。于是,可以将这个问题转化为:修改一个点的值,查询一个子树的权值和。
代码
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
const int maxm=2e5+10;
int n,q,tim,cnt=2;
int c[maxn],first[maxm],st[maxn],ed[maxn],dep[maxn],apple[maxn];
int fa[maxn][20];
bool vis[maxn];
struct edge {int u,v,nxt;};
edge e[maxm];
inline int read()
{
int x=0;bool f=0;char c=getchar();
while(!isdigit(c)) {f|=c=='-';c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return f?-x:x;
}
inline void add(int u,int v)
{
e[cnt]=(edge){u,v,first[u]};
first[u]=cnt++;
}
inline void dfs(int x)
{
tim++;
st[x]=tim;
vis[x]=1;
for(int i=1;(1<<i)<=dep[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=first[x];i;i=e[i].nxt)
if(!vis[e[i].v])
{
dep[e[i].v]=dep[x]+1;
fa[e[i].v][0]=x;
dfs(e[i].v);
}
ed[x]=tim;
}
inline int lowbit(int x)
{
return x&(-x);
}
inline void update(int x,int y)
{
while(x<=n) {c[x]+=y;x+=lowbit(x);}
}
inline int query(int x)
{
int ret=0;
while(x>0)
{
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
int t=dep[a]-dep[b];
for(int i=0;(1<<i)<=t;i++)
if(t&(1<<i)) a=fa[a][i];
if(a==b) return a;
for(int j=19;j>=0;j--)
if(fa[a][j]!=fa[b][j])
a=fa[a][j],b=fa[b][j];
return fa[a][0];
}
int main()
{
n=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
add(u,v);
add(v,u);
}
dfs(1);
q=read();
for(int i=1;i<=q;i++)
{
int opt=read(),l,r,v,x;
switch (opt)
{
case 1:
{
l=read(),r=read(),v=read();
int f=lca(l,r);
update(st[l],v);
update(st[r],v);
update(st[f],(-2)*v);
apple[f]+=v;
break;
}
case 2:
{
x=read();
cout<<query(ed[x])-query(st[x]-1)+apple[x]<<"\n";
break;
}
}
}
return 0;
}