大意:
就那么些操作,没有大意
思路:
这里就简单讲一下如何实现
首先,对于一条边,它有两个顶点,那么肯定是让深度较浅的点,也就是父节点的点权来作为这条边的边权。然后最后我们要查边权的时候,只要查它对应的子节点就可以了
那么我们为了实现该操作,在原本的板子上,有三点要进行改变:
1.dfs时更新点权,也就是让边权赋给子节点
for(int i=head[id];i!=-1;i=edge[i].next)
{
ll y=edge[i].t;
if(y==p) continue;
a[y]=edge[i].l; //如果初始边权不为0,点权下放边权时要执行这一句操作
init_dfs(y,id,depth+1);
siz[id]+=siz[y];
if(siz[y]>son_val)
{
son_val=siz[y];
son[id]=y;
}
}
2.树上路径更新的时候,你稍微手玩一下就会发现两个节点的lca是不应该被更新的,所以在最后一步更新的时候,我们的代码要有所改变
ll tree_add(ll x,ll y,ll val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
add(1,idx[top[x]],idx[x],val);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
add(1,idx[x]+1,idx[y],val);//lca不查询,所以x要+1
}
当然你也可以这么写
ll tree_add(ll x,ll y,ll val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
add(1,idx[top[x]],idx[x],val);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
add(1,idx[x],idx[y],val);
add(1,idx[x],idx[x],-val);
}
其实就是把lca的更新的结果给改回去
3.查询树上路径权值和时(如果有这个操作),同理两点的lca的点权不应该被算进去,因为它对应的边不属于这两点的路径上。
ll tree_sum(ll x,ll y)
{
ll ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=sum(1,idx[top[x]],idx[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=sum(1,idx[x]+1,idx[y]);//点权下放边权操作核心代码,lca不查询,所以x要+1
return ans;
}
同理,你也可以这么写,意思我就不解释了
ll tree_sum(ll x,ll y)
{
ll ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=sum(1,idx[top[x]],idx[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=sum(1,idx[x],idx[y]);
ans-=sum(1,idx[x],idx[x]);
return ans;
}
会了这个操作之后这题你就毫无问题了
不过按惯例还是贴一下code
#include<bits/stdc++.h>
using namespace std;
#define ll int
#define endl '\n'
const ll N=1e5+10;
struct ty{
ll t,l,next;
}edge[N<<1];
ll cn=0;
ll n,k;
char op;
ll aa,b,c,rt;
ll head[N];
void add_edge(ll a,ll b,ll c)
{
edge[++cn].t=b;
edge[cn].l=c;
edge[cn].next=head[a];
head[a]=cn;
}
struct tree
{
ll l,r;
ll val;
ll add;//lazy
ll siz;
}tr[N<<2];
ll dep[N];//深度
ll fa[N],son[N];
ll siz[N];
ll mas[N],a[N];//初始序列,处理后的序列
ll cnt=0;//dfs序的时间戳
ll top[N];//所在链的顶端
ll idx[N];
void init_dfs(ll id,ll p,ll depth)
{
dep[id]=depth;
fa[id]=p;
siz[id]=1;
ll son_val=0;
for(int i=head[id];i!=-1;i=edge[i].next)
{
ll y=edge[i].t;
if(y==p) continue;
//a[y]=edge[i].l; 如果初始边权不为0,点权下放边权时要执行这一句操作
init_dfs(y,id,depth+1);
siz[id]+=siz[y];
if(siz[y]>son_val)
{
son_val=siz[y];
son[id]=y;
}
}
}
void dfs2(ll id,ll p)
{//更新链上的情况
idx[id]=++cnt;
a[cnt]=mas[id];
top[id]=p;
if(!son[id]) return;
dfs2(son[id],p);
for(int i=head[id];i!=-1;i=edge[i].next)
{
ll y=edge[i].t;
//if(y==p||y==son[id]) continue;
if(!idx[y]) dfs2(y,y);//新的链
}
}
void push_up(ll p)
{
tr[p].val+=tr[p<<1].val+tr[p<<1|1].val;
}
void build(ll p,ll l,ll r)
{
tr[p].l=l;tr[p].r=r;tr[p].siz=r-l+1;
if(l==r)
{
tr[p].val=a[l];
return;
}
ll mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
void push_down(ll p)
{
if(tr[p].add==0) return;
tr[p<<1].val+=tr[p<<1].siz*tr[p].add;
tr[p<<1|1].val+=tr[p<<1|1].siz*tr[p].add;
tr[p<<1].add+=tr[p].add;
tr[p<<1|1].add+=tr[p].add;
tr[p].add=0;
}
void add(ll p,ll l,ll r,ll val)
{
if(tr[p].l>=l&&tr[p].r<=r)
{
tr[p].val+=tr[p].siz*val;
tr[p].add+=val;
return;
}
push_down(p);
ll mid=tr[p].l+tr[p].r>>1;
if(l<=mid) add(p<<1,l,r,val);
if(r>mid) add(p<<1|1,l,r,val);
push_up(p);
}
ll sum(ll p,ll l,ll r)
{
ll ans=0;
if(tr[p].l>=l&&tr[p].r<=r)
{
return tr[p].val;
}
push_down(p);
ll mid=tr[p].l+tr[p].r>>1;
if(l<=mid) ans+=sum(p<<1,l,r);
if(r>mid) ans+=sum(p<<1|1,l,r);
return ans;
}
ll tree_sum(ll x,ll y)
{
ll ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=sum(1,idx[top[x]],idx[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=sum(1,idx[x]+1,idx[y]);//点权下放边权操作核心代码,lca不查询,所以y要+1
return ans;
}
ll tree_add(ll x,ll y,ll val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
add(1,idx[top[x]],idx[x],val);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
add(1,idx[x]+1,idx[y],val);//同上一句注释
}
void trson_add(ll x,ll val)
{
add(1,idx[x],idx[x]+siz[x]-1,val);
}
ll trson_sum(ll x)
{
return sum(1,idx[x],idx[x]+siz[x]-1);
}
void solve()
{
cin>>n>>k;
for(int i=1;i<n;++i)
{
cin>>aa>>b;
add_edge(aa,b,0);
add_edge(b,aa,0);
}
init_dfs(rt,0,1);
dfs2(rt,rt);
build(1,1,n);
while(k--)
{
cin>>op>>aa>>b;
if(op=='P')
{
tree_add(aa,b,1);
}
else cout<<tree_sum(aa,b)<<endl;
}
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
memset(head,-1,sizeof head);
rt=1;
solve();
return 0;
}